Compare commits

..

251 commits
main ... 6.0.17

Author SHA1 Message Date
Abe Jellinek
47610d0faa Scaffold: Autocomplete translator IDs in setTranslator() calls 2022-11-01 16:38:01 -04:00
Abe Jellinek
42e042c6c6 Scaffold: Fix copying JSON test data
Previously only copied '[object Object]'.
2022-11-01 16:05:54 -04:00
Dan Stillman
b9a5fd9f78 Fix error copying from note if note Quick Copy format is "HTML"
In this case, Note Markdown wouldn't be preloaded, but it's always used
for copying from the note editor, and since the note editor uses
`noWait`, this would result in "Code promise is not resolved in noWait
mode".
2022-11-01 03:57:50 -04:00
Dan Stillman
cbb524d257 Fix Quick Copy drag after reiniting translators
Zotero.Translators.reinit() didn't reinit Quick Copy, so if an export
translator was selected it wouldn't be preloaded again and dragging
would fail with "Code promise is not resolved in noWait mode".
2022-11-01 03:57:50 -04:00
Dan Stillman
93ea818bf2 Update version 2022-11-01 03:57:50 -04:00
Dan Stillman
d2243cc339 Update translators 2022-10-31 19:11:56 -04:00
Dan Stillman
f06267e4cd Update styles and translators 2022-10-31 17:40:00 -04:00
Dan Stillman
624101832e Update locales from Transifex 2022-10-31 17:34:24 -04:00
Martynas Bagdonas
6bc1551f7f Increase wait time for pdf-reader iframe initialization in tests
This is necessary until a proper initialization promise is added to pdf-reader.
2022-10-31 18:03:42 +02:00
Dan Stillman
a8a0cabcc4 Fix HiDPI icon for webpages 2022-10-31 05:43:17 -04:00
Dan Stillman
9d80c54d5d Update repotime 2022-10-31 05:18:06 -04:00
Adomas Venčkauskas
1c8554d527 Make colored tagging via keyboard layout independent
Report https://forums.zotero.org/discussion/100717/tag-number-shortcut-with-mac-raccourci-clavier-pour-marqueurs-avec-un-mac
2022-10-31 09:45:56 +02:00
Dan Stillman
5cea183ae3 Avoid infinite/excessive loops in Find Available PDF
https://forums.zotero.org/discussion/100634/potential-infinite-loop-when-trying-to-find-available-pdf

Closes #2883
2022-10-30 04:53:09 -04:00
Dan Stillman
92434dbb78 Update Mac Word automation settings instructions for Ventura 2022-10-30 04:53:08 -04:00
Dan Stillman
2c5a91682e Fix comment for Zotero.Attachments.getPDFResolvers() 2022-10-29 04:43:23 -04:00
Dan Stillman
3cc54eaf95 Retry only twice on error in Find Available PDF
Not three times
2022-10-29 04:43:23 -04:00
Dan Stillman
7f91a0c1a8 Fix hang on 500 from site during Find Available PDF
Find Available PDF has its own domain-based retry logic that predated
automatic 5xx retries in Zotero.HTTP, so disable the latter and fix some
bugs in the former.

Fixes #2700
2022-10-29 04:43:23 -04:00
Adomas Venčkauskas
77fdc8e40c Truncate long citation text in citation dialog. Closes #2879 2022-10-28 15:09:35 +03:00
Dan Stillman
c5a769285b Update translators 2022-10-26 06:55:49 -04:00
Dan Stillman
fe09afa0a6 Restore cell.csl for style tests
Removed in 4e1754b960
2022-10-26 05:14:47 -04:00
Dan Stillman
ab2bec936e Reset accidental change from 7fcc1d35 2022-10-26 04:38:19 -04:00
Adomas Venčkauskas
af66712c77 Update SingleFile. Closes #2880 2022-10-25 15:57:54 +03:00
Adomas Venčkauskas
7db16843b3 Add an integration test for citation merging 2022-10-25 14:55:19 +03:00
Adomas Venčkauskas
a4eafd0307 Fix wrong given name disambiguation after editing author for citeproc-js
Closes #2870
2022-10-25 14:55:16 +03:00
Adomas Venčkauskas
4e1754b960 Change integration test citation style to APA and some refactoring 2022-10-25 14:55:16 +03:00
Dan Stillman
238c7ce410 Update locales from Transifex and merge new English strings 2022-10-24 21:13:24 -04:00
Dan Stillman
8a15e5abe0 Don't localize "Markdown" in Quick Copy settings 2022-10-24 19:53:42 -04:00
Dan Stillman
159c112257 Add Zotero.Utilities.Internal.stringWithColon() for localized colons
Generally just a colon, but, e.g., French adds a space before it. We'll
want to replace uses of `punctuation.colon` with this.
2022-10-24 19:49:10 -04:00
Dan Stillman
70f9462913 Merge pull request #2676 from mrtcode/note-html-export-links
Add "Include Zotero Links" option for note export and QuickCopy
2022-10-22 16:47:18 -04:00
Dan Stillman
4b5e2eae1b Update translators 2022-10-22 16:42:24 -04:00
Dan Stillman
c4876fd5ae Adjust layout of Quick Copy note format options
Also:

- Hide format options until translators are loaded (since otherwise
  the checkboxes don't have labels and the layout is messed up)
- Remove unnecessary "zotero-" prefix from the new elements
2022-10-22 16:41:48 -04:00
Dan Stillman
7fcc1d35a4 Reset note Quick Copy pref on upgrade if set to Markdown + Rich Text
The default JSON pref value used spaces, but changing the drop-down
resulted in a version without spaces, so simply changing the default to
include the new link options wouldn't change all existing installs and
the "Include App Links" checkbox wouldn't show as enabled for Markdown.
This adds a pref migration step to reset the pref to the new default if
it's set to Markdown + Rich Text, regardless of whitespace differences.
2022-10-22 16:41:48 -04:00
Martynas Bagdonas
d0d3ed731d Add "Include Zotero Links" option for note export and QuickCopy
Fixes #2349
2022-10-22 16:41:48 -04:00
Dan Stillman
f2bfaeb7a9 Fix error message for invalid field in Item.setField()
The error message was showing a field instead of an item type.

https://forums.zotero.org/discussion/100598/error-1533410729-impossible-to-correct-date-field-in-items-added-with-zotero-conector-ver-6-0-15
2022-10-22 05:28:02 -04:00
Adomas Ven
2fa67bae64
Adds support for merging adjacent citations (#2875) 2022-10-21 03:17:35 -04:00
Dan Stillman
a2db01c633 Merge new English strings 2022-10-18 00:00:46 -04:00
Dan Stillman
2b9e9c174f Don't match all attachments with annotations for "not" search conditions
Fixes #2867
2022-10-17 23:59:29 -04:00
Dan Stillman
aa0ef7012c PDF reader: Hide "Rotate Page 180°" menu option for now
Rotating will speed up with Zotero 7, so maybe we can do without this.
2022-10-17 23:59:07 -04:00
Dan Stillman
73306ee5fb PDF reader: Add "Page" to rotate menu options for clarity 2022-10-17 23:58:52 -04:00
Martynas Bagdonas
d8d6054927 Add rotation options to Edit menu to rotate the current PDF page 2022-10-17 12:26:47 +03:00
Dan Stillman
410ebc288b Update locales from Transifex 2022-10-14 17:17:48 -04:00
Martynas Bagdonas
55095ba354 Reduce loaded tabs limit if the system has 8 GB or less memory 2022-10-14 11:13:02 +03:00
Dan Stillman
3ba6343668 Merge new English strings 2022-10-12 05:04:49 -04:00
Dan Stillman
d37aa37629 Update note-editor and pdf-reader submodules 2022-10-12 05:03:09 -04:00
Dan Stillman
3582405f55 Default to UTF-8 when indexing text file without detected charset
https://forums.zotero.org/discussion/94637/indexing-of-markdown-plain-text-attachments-with-md-extension
2022-10-12 05:01:10 -04:00
Martynas Bagdonas
78eb857e73 Add annotation update test to pdf-reader tests 2022-10-11 18:07:03 +03:00
Abe Jellinek
618e71b5f1 Fix last editpane tab being misaligned vertically (#2864) 2022-10-11 10:49:30 -04:00
Martynas Bagdonas
7bada8ce0c Tweak pdf-reader annotation creation test 2022-10-10 17:09:30 +03:00
Martynas Bagdonas
af436d34a8 Add pdf-reader annotation creation test 2022-10-10 16:53:42 +03:00
Dan Stillman
e45becce2a Tweak text in LABD auto-relinking dialogs (#2374, #2092) 2022-10-08 02:29:39 -04:00
Abe Jellinek
fb4f7b7932 Automatically relink attachments from LABD (#2374)
Fixes #2092
2022-10-08 02:29:31 -04:00
Dan Stillman
fd8aa4433c Change connector server response to "Zotero is running"
People are confused by "Zotero Connector Server is Available". I'm not
sure if this will be any better, but not mentioning the connector might
help -- that seems to be part of the problem.

We could display a longer message with a link to
https://www.zotero.org/support/kb/connector_zotero_unavailable, but this
is the /ping page that gets hit constantly, so it seems like we should
keep it short (though probably it doesn't make a difference).
2022-10-07 01:31:59 -04:00
Martynas Bagdonas
29dd0cf5dc Don't allow to rotate or delete pages for read-only PDF 2022-10-06 18:00:32 +03:00
Martynas Bagdonas
28329aa785 Fix annotation image saving to cache for read-only annotations 2022-10-06 17:32:51 +03:00
Martynas Bagdonas
c5d418fc16 Fix annotation saving regression 2022-10-06 16:43:58 +03:00
Martynas Bagdonas
e9c6c76e79 Properly handle errors when trying to open too large (>2GB-1) PDF file 2022-10-06 10:57:04 +03:00
Martynas Bagdonas
f13966894f Update pdf-reader submodule 2022-10-06 09:37:01 +03:00
Martynas Bagdonas
b7cc1d549b Fix pref observer handler unregistering 2022-10-05 14:09:39 +03:00
Dan Stillman
9a3f8dbc94 Update locales from Transifex 2022-10-05 02:45:05 -04:00
Martynas Bagdonas
b594ad0b0a Allow importing annotations in group libraries 2022-10-04 14:22:54 +03:00
Martynas Bagdonas
4dd1851140 Don't allow pdf-reader to set annotation author name
Fixes the issue when your own created annotation becomes grayish and indicates that it was modified by another user.
2022-10-04 13:59:16 +03:00
Martynas Bagdonas
006dd20d5b Re-render annotation images when rotating a page
Fixes #2824
2022-10-03 17:03:32 +03:00
Adomas Venčkauskas
55afe7c08d Fix item list row text not read when using non-contiguous kb selection
Closes #2830
2022-10-03 15:20:38 +03:00
Dan Stillman
9fadfac7ee Add 15 and 16 as note font size options in menu
https://forums.zotero.org/discussion/100079/notebook-fonts
2022-10-03 06:43:28 -04:00
Martynas Bagdonas
38ae3a2600 Remove PDF view rotation options 2022-10-03 13:14:37 +03:00
Dan Stillman
473dd2ed64 Update pdf-reader submodule 2022-09-30 17:30:57 -04:00
Dan Stillman
e3b1cbd4eb Update version 2022-09-30 17:30:29 -04:00
Dan Stillman
3b93147052 Update locales from Transifex 2022-09-30 16:52:13 -04:00
Dan Stillman
b9a1e93518 Merge new English strings 2022-09-30 16:09:56 -04:00
Dan Stillman
99084084d4 Remove default OpenURL gateway
https://www.worldcat.org/registry/gateway is no longer supported -- see
https://forums.zotero.org/discussion/comment/418373/#Comment_418373 for
details

If no resolver is selected, show an error on "Library Lookup" with a
button to open the prefs.
2022-09-30 16:08:12 -04:00
Dan Stillman
64047f181a Remove stray "aaa" in "Split Horizontally" in PDF window
From 12b1897478
2022-09-30 15:33:00 -04:00
Dan Stillman
12b1897478 Swap "Split Vertically" and "Split Horizontally" in PDF reader 2022-09-30 04:22:48 -04:00
Dan Stillman
8fc9ebe4ab Update locales from Transifex and merge new English strings 2022-09-30 02:59:52 -04:00
Dan Stillman
5162845179 Update version 2022-09-30 02:52:48 -04:00
Martynas Bagdonas
2569ad6506 Update note-editor submodule 2022-09-30 09:45:41 +03:00
Martynas Bagdonas
4fdf43ed92 Prevent error when creating a note from annotations that have ink 2022-09-30 09:44:27 +03:00
Martynas Bagdonas
9691fcafc2 Import external annotations before trying to add a note from annotations 2022-09-30 09:40:35 +03:00
Martynas Bagdonas
6aad0cbb9c
Add split view for PDF reader (#2832) 2022-09-29 13:25:58 +03:00
Dan Stillman
a7e6fc330c Update locales from Transifex 2022-09-28 05:09:52 -04:00
Dan Stillman
677499865a Update translators and CSL locales 2022-09-28 04:50:28 -04:00
Dan Stillman
0e60389ee4 Update note-editor submodule 2022-09-28 04:28:56 -04:00
Dan Stillman
2271913e49 Add Number as items list column option
https://forums.zotero.org/discussion/99844/add-columns-to-desktop-app-report-number
2022-09-22 01:48:15 -04:00
Dan Stillman
ff5e09201d Update package-lock.json 2022-09-22 01:16:11 -04:00
Dan Stillman
0b89b15f66 Update locales from Transifex and merge new English strings 2022-09-22 01:14:26 -04:00
Dan Stillman
f6e11981e3 Update pdf-reader and pdf-worker submodules 2022-09-22 01:14:26 -04:00
Dan Stillman
230fc7f2df Merge pull request #2826 from tnajdek/999-keyboard-nav-creators
Make creator buttons accessible via keyboard
2022-09-21 23:18:54 -04:00
Dan Stillman
f179f0a54f Additional tweaks for creator button keyboard access (#2826)
- Open creator type menu on ArrowUp as well
- Fix outline on Windows/Linux
- Don't show focus ring on hover, since we already show a background
2022-09-21 23:16:53 -04:00
Tom Najdek
ea09aac616 Make creator buttons accessible via keyboard #999 2022-09-21 23:16:53 -04:00
Dan Stillman
4a49ffec0a Update ESLint config 2022-09-21 22:25:34 -04:00
Martynas Bagdonas
0d09618865 Fix focusContextPane error when pressing tab in standalone PDF window
Fixes #2823
2022-09-15 11:59:03 +03:00
Dan Stillman
b96fcd41b1 Update translate submodule 2022-09-15 01:06:47 -04:00
Martynas Bagdonas
c13d17b5e6 Fix PDF reader sometimes showing UTC time and sometimes local 2022-09-13 16:38:17 +03:00
Martynas Bagdonas
eb255c5868 Convert Mendeley colors to equivalent Zotero colors on PDF open
Fixes #2820
2022-09-13 14:35:16 +03:00
Tom Najdek
88217492f9
Map annotation colors colors on import #2819 (#2822) 2022-09-12 19:57:24 -04:00
Martynas Bagdonas
64897455f4 Adjust PDF reader and context pane UI based on font size pref
Fixes #2809
2022-09-09 18:03:20 +03:00
Abe Jellinek
5015b0e4cc Hide "Find Available PDF" for feed items (#2807) 2022-09-07 10:07:43 -04:00
Martynas Bagdonas
a2d378448a Add context menu options to copy/save image from pdf-reader/note-editor
Fixes #2664
2022-09-06 16:35:14 +03:00
Dan Stillman
32b64b3cf1 Merge new English strings 2022-09-05 15:47:06 +01:00
Dan Stillman
66fccec6b4 Add "Create Note from Annotations" option to items list context menu
To allow creation of a standalone note with annotations from all the
selected top-level items and/or attachments. Annotations will be sorted
by the order of the items in the items list.

"Add Note from Annotations" remains when a single regular item or one or
more attachments under a single regular item are selected.
2022-09-05 10:37:07 -04:00
Dan Stillman
894309d061 Add collectionID option to EditorInstance.createNoteFromAnnotations()
For adding a standalone note to the current collection
2022-09-05 10:37:07 -04:00
Dan Stillman
b24c7577ec Rename Zotero.Items::keepParents() to keepTopLevel()
So that it works for more than two levels of items

Also fix a bug where the parent item could be returned more than once if
multiple child items were selected.
2022-09-05 10:37:07 -04:00
Dan Stillman
ca4ced1e9f Add Zotero.Item::topLevelItem and Zotero.Items.getTopLevel(items) 2022-09-05 10:37:07 -04:00
Martynas Bagdonas
6646be66d0 EditorInstance.createNoteFromAnnotations(): Handle multiple attachments 2022-09-05 10:37:07 -04:00
Dan Stillman
ef0811bd4c Merge new English strings 2022-09-02 12:07:13 +02:00
Martynas Bagdonas
f893206dfd Allow inserting images over context menu
Fixes #2759
2022-09-01 11:49:30 +03:00
Martynas Bagdonas
ae5de2c2f5 Update pdf-reader submodule 2022-08-31 15:45:56 +03:00
Martynas Bagdonas
a3b45a74e9 Add missing noteEditor.mathBlock string 2022-08-31 14:08:42 +03:00
Dan Stillman
e474ca524b Update pdf-reader submodule 2022-08-30 11:38:44 +02:00
Dan Stillman
bc0f6203e1 Update note-editor submodule 2022-08-30 11:18:07 +02:00
Dan Stillman
91ae576074 Fix HTTP.request() 5xx handling with errorDelayMax=0
This was causing delay-less infinite loops for OPTIONS requests to Box,
which are returning 502 errors.
2022-08-29 23:44:55 +02:00
Abe Jellinek
c255104ada duplicateAndConvertSelectedItem: Don't copy abstracts (#2799) 2022-08-29 16:27:26 -04:00
Dan Stillman
75f5d6aca1 Merge new English strings 2022-08-25 17:34:41 -04:00
Martynas Bagdonas
d156bef42a Update note-editor submodule and strings for math and table insertion 2022-08-25 14:19:38 +03:00
Dan Stillman
79246196ac Use items-list sort order for report from collection or saved search
https://forums.zotero.org/discussion/99284/exporting-a-report-sorted-by-first-date

Regression from HTML tree
2022-08-25 00:47:57 -04:00
Adomas Venčkauskas
262e1964ae Fix SingleFile snapshot saving stalling in Firefox Connector
Update SingleFile submodule
2022-08-24 11:48:02 +03:00
Dan Stillman
f4dfea6849 Don't repeatedly upload relations
Fixes #2772
2022-08-22 01:12:31 -04:00
Dan Stillman
999f78b0f5 Update translators 2022-08-21 23:30:39 -04:00
Dan Stillman
2e6321a4bf Update version 2022-08-21 23:29:48 -04:00
Tom Najdek
35a1bb20cb Make citavi annotations importer more resilient 2022-08-19 11:20:24 -04:00
Tom Najdek
8c80ea431e Fix importing Citavi annotations in some cases 2022-08-19 11:20:24 -04:00
Dan Stillman
3abd720957 Update pdf-reader submodule 2022-08-19 02:50:22 -04:00
Dan Stillman
8379540719 Include proper test for b373291c02 for #2771 2022-08-19 02:47:24 -04:00
Dan Stillman
b373291c02 Fixed filed items with annotations appearing in Unfiled Items
Fixes #2771

Regression from 20c6fe67
2022-08-19 00:15:55 -04:00
Abe Jellinek
3391f3bc99
Empty Trash: Visually remove deleted items, refresh icon (#2606)
There were a few problems causing the incorrect behavior:
1. Rows were being removed only if they had no non-deleted children, which
   wasn't the right check. We want to remove all rows with no *deleted*
   children.
2. Children of the removed rows weren't being removed with them.
3. We weren't invalidating the tree (which _removeRows() doesn't do).

Also:

* Erase trashed annotation after getAnnotations() test

Because ItemTree#notify() doesn't yet correctly handle refresh events on
parent items that are themselves children (three-level nesting: item ->
attachment -> annotation), this test was causing a failure in
itemTreeTest.js.
2022-08-18 21:14:34 -04:00
Martynas Bagdonas
6ca854a018 Fix navigation to annotation when opening an unloaded PDF reader tab
Regression from 142e3b09
2022-08-18 10:21:37 +03:00
Martynas Bagdonas
fa32eb6790 Fix regression for broken "Snow in Page"
Fixes #2764
Regression from 7ec54fd
2022-08-18 10:21:37 +03:00
Abe Jellinek
96c4427d6c Scaffold: Non-async detectWeb and async scrape by default
We don't usually want an async detectWeb, since HTTP requests should only be
used there in very exceptional cases. We do usually want an async scrape (and we
were already - mistakenly - awaiting it).
2022-08-17 16:34:19 -04:00
Dan Stillman
5a8b5a1829 Update localized string for pdf-reader 2022-08-17 03:46:27 -04:00
Dan Stillman
f368a53311 Fix and disable item-tree test for emptying trash
20c6fe6737 caused this to start failing, but only because the test was
testing something too specific. The change in that commit caused more
rows to be left behind when emptying the trash (for reasons I should
probably look into), but the trash wasn't being emptied properly before,
which #2606 should fix. This test should be restored as part of that PR.
2022-08-17 01:53:21 -04:00
Dan Stillman
49020b02a2 Update pdf-reader submodule 2022-08-17 00:03:34 -04:00
Dan Stillman
20c6fe6737 Match parent attachments for annotation tags
Expose annotation tags in tag selector and match parent attachments when
filtering/searching

This also fixes searching for annotation text or comments when using
Everything quick search.

This is temporary until we display annotations in the items list
directly.
2022-08-16 22:56:39 -04:00
Dan Stillman
80351a496b Update version 2022-08-16 22:56:39 -04:00
Dan Stillman
2d2e787111 Update translators 2022-08-15 08:32:57 -04:00
Dan Stillman
eaba3ae099 Update locales from Transifex 2022-08-15 08:32:17 -04:00
Dan Stillman
4746300d33 Update pdf-reader submodule 2022-08-15 08:24:17 -04:00
Dan Stillman
85b0c9dbad Fix importing of standalone attachments without URLs
And allow `importSnapshotFromFile()` without `parentItemID` or
`libraryID`, which is more consistent with other attachment functions

Follow-up to 318e4852e9

https://forums.zotero.org/discussion/comment/414802/#Comment_414802
2022-08-14 05:06:27 -04:00
Dan Stillman
318e4852e9 Fix importing of standalone attachments
Maybe has been broken for years?

https://forums.zotero.org/discussion/99020/warning-data-loss-when-exporting-collections
2022-08-13 16:23:00 -04:00
Dan Stillman
3dc3359cff Don't relate book sections to each other when creating from book
Fixes #2757
2022-08-13 05:45:23 -04:00
Dan Stillman
b505c630d3 Fix copying of standalone attachments between libraries
Regression in f684984b07 (maybe a race condition)
2022-08-13 02:00:41 -04:00
Dan Stillman
21b7baee35 Update translators 2022-08-12 00:38:19 -04:00
Dan Stillman
df59cee94a Update global schema for locales 2022-08-12 00:34:21 -04:00
Dan Stillman
d1275f9964 Update locales from Transifex and merge new English strings 2022-08-12 00:33:08 -04:00
Abe Jellinek
d4a7de2e8d
Add Book -> Book Section and Book Section -> Book to context menu (#2755) 2022-08-11 16:40:27 -04:00
Adomas Venčkauskas
864fd03c87 Prevent singlefile config from overwriting the Zotero.SingleFile namespace 2022-08-11 13:44:48 +03:00
Adomas Venčkauskas
d3cb7c86d9 Update SingleFile config for current version
They got updated upstream and the backwards-compat code
does not run for the way we execute singlefile

See https://github.com/gildas-lormeau/SingleFile/issues/1021
Addresses https://github.com/zotero/zotero-connectors/issues/398
2022-08-11 13:43:39 +03:00
Martynas Bagdonas
e4e3c72036 Fix PDF reader selector popup that was never opening 2022-08-11 12:18:32 +03:00
Martynas Bagdonas
0857cefb0c Fix regression preventing opening PDF reader window when the tab is open 2022-08-11 12:18:32 +03:00
Dan Stillman
9b7b4fe134 Improve test for event-title substitution
And add comments

Follow-up to 20d0f103f
2022-08-10 01:34:57 -04:00
Dan Stillman
a9c3fc7790 Reset Zotero.locale to 'en-US' after cite test 2022-08-10 01:01:48 -04:00
Dan Stillman
20d0f103fd Automatically substitute event-title for event in styles
Stopgap until styles are updated in citation-style-language/styles#6151
2022-08-10 01:01:48 -04:00
Abe Jellinek
20eca3781d Add test for 87455d 2022-08-08 11:48:33 -04:00
Abe Jellinek
87455d28c3 Item box: Fix fieldMode resetting after editor hidden twice
hideEditor() called switchCreatorMode() too early, setting the fieldMode
attribute on the soon-to-be-discarded textbox instead of the label
replacing it. Then, showing the editor a second time would carry over an
empty fieldMode attribute from the label to the new textbox. Hiding that
editor would update the creator in the item to fieldMode = 0 and trigger
a save.

Moving the switchCreatorMode() call does the trick, and the flex
settings changes still work fine when made there.
2022-08-08 10:56:56 -04:00
Abe Jellinek
2048319541
Advanced Search: Make sure items are loaded (#2743) 2022-08-06 15:00:33 -04:00
Dan Stillman
d03b0a716d Don't preselect Act for multiple sources in classic citation dialog
"Multiple Sources…" wasn't properly handled by 629892b0b8

https://forums.zotero.org/discussion/98877/act-instead-of-page
https://twitter.com/drezvera99/status/1554521940684984320
2022-08-06 02:29:26 -04:00
Abe Jellinek
bb2b37a73a Item box: Prevent tabbing to hidden fields
This one's probably been around for a while! Reproduce by creating an
item with a fieldMode = 1 creator, tabbing past the creator, and then
shift-tabbing back to it. Your cursor will end up in the invisible first
name field and further shift-tabs can't move it past.

Cherry-picked from fx102: 080ada78ee
2022-08-05 16:31:09 -04:00
Martynas Bagdonas
7ec54fdaa9 Select existing unloaded tab instead of opening a new one
Fixes #2740
2022-08-05 18:22:30 +03:00
Martynas Bagdonas
5a659b070d Allow to scroll tabs with mouse wheel
Fixes #2724
2022-07-29 13:06:33 +03:00
Abe Jellinek
ad96323881
Duplicates Merge: Preserve embedded annotations (#2728) 2022-07-29 05:06:44 -04:00
Adomas Venčkauskas
fc0f6157d0 Do not load-timeout on browser PDF download during content load
Closes #2726
2022-07-26 13:49:23 +03:00
Martynas Bagdonas
6733f2edca Freeze note schema version to 8
We can do it because it was only used to create a note from annotations.

No need to update schema version in Zotero client, unless using new
features when creating a note from annotations.
2022-07-25 18:04:00 +03:00
Martynas Bagdonas
e1997620a4 Fix regression that prevents showing the last selected tab on startup
Fixes #2723
2022-07-25 11:51:05 +03:00
Dan Stillman
a396771cbc Update version 2022-07-23 03:56:26 -04:00
Dan Stillman
0e0997078b Update global schema 2022-07-23 03:26:40 -04:00
Martynas Bagdonas
0785b3a086 Fix regression that prevents showing new notes in contextPane notes list 2022-07-21 13:27:32 +03:00
Adomas Venčkauskas
ba5cb7d5c6 Fixes some assets not being saved with SingleFile snapshots
Part of zotero/zotero-connectors#394

When saving an item (e.g. on arxiv) with a site translator, the
translator may add a custom snapshot attachment URL which does not match
the translation URL (the URL in the browser where translation was
initiated) in which case Zotero handles snapshot saving. Zotero loads
the page in a background browser. By default images are not loaded in
this browser. SingleFile due to CORS restrictions has to refetch all
resources that are not from the same domain or subdomain, but uses
pre-loaded resources (images) from the same domain. Before this change
any images that were from the same domain as the saved website were not
saved in the snapshot. This commit fixes that.
2022-07-20 14:28:56 +03:00
Adomas Venčkauskas
d822da4c06 Changes for updated SingleFile submodule 2022-07-20 14:28:56 +03:00
Adomas Venčkauskas
a297692487 Update SingleFile submodule 2022-07-20 14:28:56 +03:00
Dan Stillman
6921268dc0 Localize "Export PDF…" menu option
Fixes #2710
2022-07-20 01:04:00 -04:00
Dan Stillman
ba1906c054 Update version 2022-07-18 23:10:31 -04:00
Dan Stillman
b5be7cbd57 Update note-editor submodule 2022-07-18 19:47:23 -04:00
Dan Stillman
5c61815f36 Update translate submodule 2022-07-18 19:43:18 -04:00
Dan Stillman
b5ca5aed3a Update submodules 2022-07-18 19:14:24 -04:00
Dan Stillman
4b6598acc4 Update locales from Transifex 2022-07-18 08:57:41 -04:00
Dan Stillman
14a6ce000e Disable sort tests from 26a5e2900a for now
Until I can figure out the race-condition breakage they trigger later in
the file
2022-07-18 08:56:57 -04:00
Dan Stillman
9d0cd005f8 Increase Mendeley API timeout to 60 seconds
To see if we can fix the 30-second timeout here:

https://forums.zotero.org/discussion/comment/412750/#Comment_412750
2022-07-18 08:29:45 -04:00
Dan Stillman
26db75971e Update pdf-reader submodule 2022-07-18 03:51:09 -04:00
Dan Stillman
cc45e9019b Apply Big Sur styling when macOS version comes through correctly
Follow-up to zotero/zotero-standalone-build@f7a506a32 -- now that some
people are somehow getting an accurate macOS version number, we need to
apply the Big Sur CSS to all higher versions.

https://forums.zotero.org/discussion/98406/zotero-will-not-open-mac-os-monterey
2022-07-17 05:09:05 -04:00
Dan Stillman
98d6f40e4a Add warning in toolbar for 'dev' channel builds 2022-07-16 04:19:42 -04:00
Martynas Bagdonas
2cad5b00d1 Use Quick Copy (Markdown) for direct plain-text copying from note-editor
Fixes #2505
2022-07-15 15:06:19 +03:00
Abe Jellinek
95239db0fd Prevent deleting My Publications
Previously showed a blank confirmation dialog and logged an error.
2022-07-13 16:23:50 -04:00
Martynas Bagdonas
4c063e7b6e Prevent delayed context pane expansion and pdf-reader rerender/resize when switching from library tab 2022-07-12 18:00:21 +03:00
Martynas Bagdonas
07f1517712 Don't include quotes when {{highlight}} is placed in a blockquote
Fixes #2697
2022-07-12 12:12:21 +03:00
Martynas Bagdonas
f0e0971c69 Include quotation marks for highlights by default, but allow to disable
Fixes #2697
2022-07-11 15:32:02 +03:00
Dan Stillman
acba90f272 Fix test failure after 26a5e2900a 2022-07-11 05:19:18 -04:00
Dan Stillman
26a5e2900a Better fix for errors from invalid sort fields
Just catch the error from `ItemTree::sort()` and clear the
secondary-sort and fallback-sort prefs so that sorting works on the next
attempt.

Replacement for a8ed30ce80

https://groups.google.com/g/zotero-dev/c/kc0-C6-SA74/m/bhHniGceAQAJ
2022-07-11 01:30:38 -04:00
Dan Stillman
34d66381d1 Revert "Validate fields in ItemTree::getSortFields()"
This reverts commit a8ed30ce80 and related
commits.

We'll address breakage from invalid sort fields another way, without
inconveniencing plugin authors.

https://groups.google.com/g/zotero-dev/c/kc0-C6-SA74/m/bhHniGceAQAJ
2022-07-11 00:43:15 -04:00
Dan Stillman
f7dbcdde4b Sort empty rows last for Date/Year columns when descending
Date columns start in descending order, so put empty rows at end

Also remove a seemingly unnecessary exception for Title when not the
primary sort and just always sort it with empty rows first
2022-07-10 23:47:02 -04:00
Dan Stillman
c4563af381 Fix sorting of attachments and notes columns
Regression from a8ed30ce80
2022-07-10 23:26:36 -04:00
Dan Stillman
56e7f0a10f Fix sorting by Item Type and feed item itemID
Regression from a8ed30ce80
2022-07-10 17:31:01 -04:00
Dan Stillman
3a160b2630 Increase downloadPDFViaBrowser.onLoadTimeout to 3000
Apparently necessary for some people to get PDFs on ScienceDirect. We
should come up with a better way of detecting the page load if we can,
so that we can avoid this long of a timeout for people who just will
never have access to ScienceDirect PDFs.

https://forums.zotero.org/discussion/comment/411056/#Comment_411056

Addresses #2698
2022-07-10 06:40:32 -04:00
Dan Stillman
124c18d54d CookieSandbox: Fix error setting request cookies
Regression from 6af3b0276a, showing up as "trackedBy is undefined" error

https://forums.zotero.org/discussion/98322/no-snapshot-or-pdf-autosaved-using-zotero-connector-on-safari
2022-07-10 06:28:56 -04:00
Dan Stillman
57c582e171 Merge new English strings 2022-07-09 18:08:38 -04:00
Dan Stillman
cf8819cc06 Add localized string for timestamp CSL locator
Not included in the CSL locales:

https://forums.zotero.org/discussion/comment/412060/#Comment_412060
2022-07-09 18:07:07 -04:00
Dan Stillman
fe74b02d28 Merge new English strings 2022-07-09 01:56:56 -04:00
Dan Stillman
1dcc2728dd Tweak confirmation message for recursive collection-item removal
I guess the "its" is technically a little clearer, but it's a bit
awkward, and I think it's reasonably implied.
2022-07-09 01:54:07 -04:00
Dan Stillman
c5dbf0169f
Merge pull request #2693 from tnajdek/mendeley-import-improve-feedback
Multiple improvements to Mendeley importer
2022-07-09 01:43:50 -04:00
Abe Jellinek
3f282fc25f
recursiveCollections: Remove from all subcollections on delete (#2689) 2022-07-09 01:37:14 -04:00
Dan Stillman
7163a196f8 Update pdf-reader and pdf-worker submodules 2022-07-09 01:32:45 -04:00
Dan Stillman
8c0499468e Update locales from Transifex 2022-07-09 01:28:18 -04:00
Dan Stillman
629892b0b8 Add CSL 1.0.2 locators and switch to CSL locales for localization
And move Page to middle of list, while still selecting by default

https://forums.zotero.org/discussion/comment/396602/#Comment_396602
2022-07-09 01:00:07 -04:00
Dan Stillman
2ff67c987e Fix test failure after a8ed30ce8
We added a `toggleSort()` call on the title, so then when called again
it reverses the direction. To avoid, sort by creator and then title in
the second test.
2022-07-08 06:44:10 -04:00
Dan Stillman
a8ed30ce80 Validate fields in ItemTree::getSortFields()
To avoid startup hang if a plugin does something bad:

https://forums.zotero.org/discussion/comment/411843/#Comment_411843

Fixes #2692
2022-07-08 06:01:23 -04:00
Tom Najdek
43f15e7517
Improve log output for multiple Mendeley imports
Helps with debugging cases where new import is started while previous
one is still being cancelled
2022-07-07 13:40:40 +02:00
Tom Najdek
df11227e0a
Lint code related to Mendeley importer 2022-07-07 13:40:40 +02:00
Tom Najdek
d418d79e70
Fix a bug in regex extracting fields to "extra"
Because regex is built using a template string, \s* is actually escaped
into s*, i.e. literal "s" appearing 0 or more times. In most cases this
would mean that output can have spacing slightly off. In extreme case,
when identifier starts with letter "s", this could this could lead to
identifier being stored incorrectly.

Also adjusted tests to be more strict and mock data to cover this case.
2022-07-07 13:40:40 +02:00
Tom Najdek
42aebccbf4
Mendeley import: detect win close, better feedback
* Detect wizard cancel/close and interrupt import. This will still
  have to wait for current fetch (file or metadata) to complete but will
  then advance to the cleanup stage
* Advance progress bar during metadata fetch
* Add some extra logging
2022-07-07 13:40:33 +02:00
Tom Najdek
7b6e19435b
Don't try to remove temporary dir after import
Previously we had a structure that also created folders in temp dir,
that has since changed but code in cleanup phase to remove containing
dir has been accidentally left unremoved.
2022-07-07 10:09:53 +02:00
Martynas Bagdonas
f650f95081 Fix disabled "Add to Note" when a child note is open
Fixes #2687
2022-07-06 11:33:22 +03:00
Dan Stillman
0357026865 Update global schema and utilities for CSL 1.0.2 2022-07-05 01:34:10 -04:00
Martynas Bagdonas
92d89becc7 Adjust page rotation labels in PDF reader
Fixes #2669
2022-07-01 16:33:08 +03:00
Martynas Bagdonas
49f9642c0d Show parent item title for child notes in context pane
Fixes #2681
2022-07-01 15:32:14 +03:00
Dan Stillman
94372111f5 Update pdf-reader submodule 2022-07-01 04:32:42 -04:00
Martynas Bagdonas
f0b896d282
Implement smart notes switching in contextPane (#2671)
Fixes #2650
2022-07-01 03:28:20 -04:00
Dan Stillman
ec68216310 Update version 2022-06-24 01:05:08 -04:00
Dan Stillman
b215d93ac9 Update utilities submodule and date-parsing tests
Includes strToDate() fixes
2022-06-22 04:41:33 -04:00
Dan Stillman
bf1480f8f0 Update locales from Transifex 2022-06-21 23:05:20 -04:00
Dan Stillman
6f089445a5 Update translators 2022-06-21 22:17:44 -04:00
Martynas Bagdonas
14e62ee34f Update pdf-reader and note-editor, use specific prebuilds, tweak code 2022-06-17 16:47:53 +03:00
Adomas Venčkauskas
43c86c0e58 Limit the force-click during drag fix to macOS (4fb0661b) 2022-06-15 09:08:30 +03:00
Adomas Venčkauskas
6f3f5d2ea8 Fix alt-arrow not working on macOS when editing collection names.
Fixes #2651
2022-06-14 14:27:34 +03:00
Adomas Venčkauskas
4fb0661b50 Fix force-click during drag sometimes causing collections to switch
Closes #2652
2022-06-14 14:18:36 +03:00
Abe Jellinek
57ab92b5b9 Fix error if New Collection prompt is canceled 2022-06-09 18:32:14 -05:00
Dan Stillman
7b20972c27 Use String.fromCharCode() to load Chinese characters in strToDate() test
Follow-up to dc045250a6
2022-06-09 00:03:34 -04:00
Dan Stillman
dc045250a6 Fix parsing of Chinese and other non-ASCII month names
https://forums.zotero.org/discussion/97683/bug-locale-issues-concerning-zotero-and-zotero-connector
2022-06-08 23:45:18 -04:00
Dan Stillman
256bd157ed Properly strip ZWJ in isOnlyEmoji() 2022-06-07 20:36:48 -04:00
Dan Stillman
2b45b7fea3 Fix Emoji detection
And move to Zotero.Utilities.Internal.isOnlyEmoji()

Fixes #2643
2022-06-07 20:12:29 -04:00
Dan Stillman
1d5fd1308a Update styles submodule 2022-06-07 03:36:10 -04:00
Abe Jellinek
d8069fac50
Fix sorting by attachment (#2586) 2022-06-07 01:32:27 -04:00
Dan Stillman
18516a33d9 Update locales from Transifex and merge new English strings 2022-06-07 01:25:57 -04:00
Dan Stillman
b658f09dd8 citeproc-js: Add space after left margin in plain-text mode
This adds a space after the the number in some numeric styles ("[1]" in
IEEE style, "1." in Nature) when pasting bibliography entries into a
plain-text editor.

Some styles (ACS, AMA, Vancouver) will need to be updated to remove
their hard-coded spaces to avoid double spaces after this change.

Patch from @zepinglee

Fixes #2633
2022-06-07 00:57:01 -04:00
Martynas Bagdonas
5799bdd554
Add support for PDF page deletion and rotation (#2595)
* Add support for PDF page deletion and rotation
Fixes #2561
2022-06-07 00:53:37 -04:00
Adomas Venčkauskas
62c7b4db2b Log full hidden browser count after its creation 2022-06-06 12:50:21 +03:00
Adomas Venčkauskas
caa0b05e5f Fix a MIMETypeHandler.removeHandler() bug 2022-06-06 12:49:58 +03:00
Adomas Venčkauskas
5095543bef Improve downloadPDFViaBrowser handlers and logging 2022-06-06 12:49:28 +03:00
Adomas Venčkauskas
6af3b0276a Fix cookieSandbox not overriding user agent if no cookies for domain.
Potential fix for #2635
2022-06-06 12:48:29 +03:00
Martynas Bagdonas
67700f8a2c Fix library tab tooltip always staying on top 2022-05-31 15:37:30 +03:00
Dan Stillman
d12f3eda61 Fix detection of some emoji set as colored tags
Emoji such as ⭐️ that began as text-based Unicode characters and depend
on Variation Selector-16 to display the emoji presentation weren't being
properly detected.
2022-05-26 06:53:36 -04:00
Dan Stillman
deabf3f042 Fix support tests after 28ed3e34b 2022-05-24 04:32:05 -04:00
Dan Stillman
28ed3e34b5 Update global schema
Includes the Preprint archiveID/number mapping for #2481
2022-05-24 03:43:36 -04:00
Dan Stillman
354183c25d Update locales from Transifex 2022-05-24 03:43:36 -04:00
Dan Stillman
b0f69ef7e3 Update note-editor submodule 2022-05-23 16:19:20 -04:00
Dan Stillman
ebc23d73b0 Add prefs for timeouts for downloading PDF via browser
1 second isn't enough for some users, so try 1.5, and allow for easier
debugging via a pref.

https://forums.zotero.org/discussion/96431/i-have-access-to-pdf-but-zotero-cannot-automatically-add-it
https://forums.zotero.org/discussion/97277/unable-to-download-papers-using-zotero-chrome-extension
2022-05-20 05:01:57 -04:00
Dan Stillman
419f74379b Feed import: Don't fail on OPML entry with no title or text
https://forums.zotero.org/discussion/96841/impossible-dimporter-ompl-rss
2022-05-20 00:33:25 -04:00
Dan Stillman
603b843f71 Update version 2022-05-17 23:54:20 -04:00
Dan Stillman
1e3959020d Update note-editor submodule 2022-05-17 04:57:06 -04:00
Martynas Bagdonas
3fd0abf6b0 Avoid error interrupting annotation extraction from multiple items 2022-05-16 13:42:44 +03:00
Dan Stillman
111a254696 Update locales from Transifex 2022-05-16 00:56:22 -04:00
Dan Stillman
69616500d8 Update translators, styles, and CSL locales 2022-05-16 00:56:13 -04:00
Dan Stillman
693f9a7e1b Try to open external PDF reader to page number for "Show on Page"
PDF-handling code from `ZoteroPane.viewAttachment()` predates
`Zotero.OpenPDF` and didn't handle page numbers for external PDF
readers, so when called from "Show on Page" in a note (via
`ZoteroPane.viewPDF()`) it just launched the file itself in the
specified handler or via the OS.

For now, change to use `Zotero.OpenPDF.openToPage()` when there's a page
number. Later we should use `Zotero.OpenPDF` for everything, but that
code is more complicated than just using `launchFile()`, so we'll need
to do some testing (particularly on Linux) to see what's best.

(Note that "Show on Page" with an external reader doesn't make a ton of
sense, since you can't actually see the annotation, but opening the
right page is better than nothing.)

Fixes #2612
2022-05-15 04:28:30 -04:00
Abe Jellinek
0c0afb129b Scaffold templates: Pull URL from doc
Link URLs could lead to redirects.
2022-05-12 14:49:30 -07:00
Abe Jellinek
a11c5987ad Fix Scaffold load error when fontSize pref is set 2022-05-10 09:10:13 -07:00
3678 changed files with 111448 additions and 459334 deletions

View file

@ -9,10 +9,16 @@
"chrome/content/zotero/xpcom/citeproc.js",
"chrome/content/ace/*",
"chrome/content/scaffold/templates/*",
"resource/react.js",
"resource/react-dom.js",
"resource/react-virtualized.js",
"test/resource/*.js"
],
"plugins": [
"@babel/plugin-proposal-class-properties",
"@babel/plugin-proposal-object-rest-spread",
"@babel/plugin-proposal-optional-chaining",
"@babel/plugin-proposal-unicode-property-regex",
[
"transform-es2015-modules-commonjs",
{

18
.eslintignore Normal file
View file

@ -0,0 +1,18 @@
build/*
chrome/content/zotero/xpcom/citeproc.js
chrome/content/zotero/xpcom/isbn.js
chrome/content/zotero/xpcom/rdf/*
chrome/content/zotero/xpcom/xregexp/*
chrome/content/zotero/xpcom/translation/tlds.js
chrome/skin/default/zotero/timeline/bundle.js
chrome/skin/default/zotero/timeline/timeline-api.js
resource/bluebird/*
resource/classnames.js
resource/csl-validator.js
resource/jspath.js
resource/prop-types.js
resource/react*
resource/schema/connectorTypeSchemaData.js
resource/tinymce/*
test/resource/*
translators/*

44
.eslintrc Normal file
View file

@ -0,0 +1,44 @@
{
"env": {
"browser": true,
"es6": true,
"node": true
},
"globals": {
"Zotero": false,
"ZOTERO_CONFIG": false,
"AddonManager": false,
"Cc": false,
"Ci": false,
"Components": false,
"ConcurrentCaller": false,
"ctypes": false,
"OS": false,
"PluralForm": false,
"Services": false,
"XPCOMUtils": false,
"XRegExp": false
},
"extends": [
"@zotero",
"plugin:react/recommended"
],
"parser": "@babel/eslint-parser",
"parserOptions": {
"ecmaVersion": 2018,
"ecmaFeatures": {
"jsx": true
},
"sourceType": "module"
},
"plugins": [
"react",
"@babel"
],
"settings": {
"react": {
"version": "17.0"
}
},
"rules": {}
}

4
.gitattributes vendored
View file

@ -1,5 +1 @@
*.sql text eol=lf
app/win/zotero.exe.tar.xz filter=lfs diff=lfs merge=lfs -text
app/mac/updater.tar.xz filter=lfs diff=lfs merge=lfs -text
app/win/updater.exe.tar.xz filter=lfs diff=lfs merge=lfs -text
app/linux/updater.tar.xz filter=lfs diff=lfs merge=lfs -text

9
.github/ISSUE_TEMPLATE.md vendored Normal file
View file

@ -0,0 +1,9 @@
**READ THIS BEFORE CREATING AN ISSUE**
Zotero does not use GitHub Issues for bug reports or feature requests.
Please post all such requests to the Zotero Forums at https://forums.zotero.org, where Zotero developers and many others can help. For confirmed bugs or agreed-upon changes, Zotero developers will create new issues in the relevant repositories.
Development questions involving code, APIs, or other technical topics can be posted to the zotero-dev mailing list at http://groups.google.com/group/zotero-dev.
See https://www.zotero.org/support/zotero_support for more information on how Zotero support works.

View file

@ -1,364 +1,85 @@
name: CI
on:
push:
pull_request:
workflow_dispatch:
schedule:
# Monthly, to catch runner image and OS changes
- cron: '0 6 1 * *'
concurrency:
group: ${{ github.ref }}
cancel-in-progress: true
on: [push, pull_request]
jobs:
# Decide whether to run the network-filesystem and Windows tests: always for manual and
# scheduled runs, and otherwise only when the changes touch the Gecko version, the files
# responsible for network-filesystem database handling, or (for Windows) the files that
# make up the Windows build
changes:
name: Detect changes
build:
name: Build, Upload, Test
runs-on: ubuntu-latest
if: >
github.event_name != 'pull_request'
|| github.event.pull_request.head.repo.full_name != github.repository
outputs:
network: ${{ steps.check.outputs.network }}
windows: ${{ steps.check.outputs.windows }}
steps:
- name: Check for network-filesystem-related changes
id: check
env:
EVENT: ${{ github.event_name }}
REPO: ${{ github.repository }}
SHA: ${{ github.sha }}
BEFORE: ${{ github.event.before }}
BASE: ${{ github.event.pull_request.base.sha }}
run: |
network=false
windows=false
if [[ "$EVENT" == "workflow_dispatch" || "$EVENT" == "schedule" ]]; then
network=true
windows=true
else
base="$BASE"
[[ -z "$base" ]] && base="$BEFORE"
git init -q repo && cd repo
git remote add origin "https://github.com/$REPO"
git fetch -q --depth 1 origin "$SHA"
# Run the tests if the base of the change can't be determined (e.g., a new
# branch or an unfetchable pre-force-push commit)
if [[ -z "$base" || "$base" == 0000000000000000000000000000000000000000 ]] \
|| ! git fetch -q --depth 1 origin "$base" 2>/dev/null; then
network=true
windows=true
else
files=$(git diff --name-only "$base" "$SHA")
if grep -qE '^(app/config\.sh|chrome/content/zotero/xpcom/(db|file)\.js|\.github/workflows/ci\.yml)$' <<< "$files"; then
network=true
windows=true
fi
if grep -qE '^app/(win/|build\.sh$|scripts/(dir_build|fetch_xulrunner|prepare_build)$)' <<< "$files"; then
windows=true
fi
fi
fi
echo "network=$network" >> "$GITHUB_OUTPUT"
echo "windows=$windows" >> "$GITHUB_OUTPUT"
test:
name: Test (${{ matrix.shard }})
runs-on: ubuntu-latest
timeout-minutes: 30
needs: changes
# Same-repo PRs are covered by the push run, so run pull_request jobs only for forks
if: >
github.event_name != 'pull_request'
|| github.event.pull_request.head.repo.full_name != github.repository
strategy:
matrix:
# Numbered shards split the full suite. 'smb' and 'nfs' run the db and file tests
# with the test data directory on a loopback CIFS or NFS mount, so that connection
# initialization itself runs against a network filesystem, which is where
# network-filesystem failures (startup crashes and hangs) occur. The network shards
# run only when the 'changes' job detects relevant changes.
shard: ${{ fromJSON(needs.changes.outputs.network == 'true'
&& '["1", "2", "3", "4", "smb", "nfs"]'
|| '["1", "2", "3", "4"]') }}
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v2
with:
submodules: recursive
lfs: true
- name: Install Node
uses: actions/setup-node@v4
uses: actions/setup-node@v2
with:
node-version: 24
node-version: 14
#cache: npm
# On GitHub
- name: Install xvfb
if: env.ACT != 'true'
run: sudo apt update && sudo apt install -y xvfb
# Local via act
- name: Install packages for act
if: env.ACT == 'true'
run: apt update && apt install -y zstd xvfb dbus-x11 libgtk-3-0 libx11-xcb1 libdbus-glib-1-2 libxt6
- name: Cache xulrunner
id: xulrunner-cache
uses: actions/cache@v4
- name: Cache Firefox
id: firefox-cache
uses: actions/cache@v2
with:
path: app/xulrunner/firefox-x86_64
key: xulrunner-${{ hashFiles('app/config.sh', 'app/scripts/fetch_xulrunner') }}
- name: Fetch xulrunner
if: steps.xulrunner-cache.outputs.cache-hit != 'true'
run: app/scripts/fetch_xulrunner -p l
path: firefox-x86_64
key: firefox-60.9.0esr
- name: Download Firefox
if: steps.firefox-cache.outputs.cache-hit != 'true'
run: wget -O tarball "https://zotero-download.s3.us-east-1.amazonaws.com/dev/firefox-60.9.0esr-x86_64-modified.tar.gz"
- name: Extract Firefox
if: steps.firefox-cache.outputs.cache-hit != 'true'
run: tar xvf tarball
- name: Cache Node modules
id: node-cache
uses: actions/cache@v4
uses: actions/cache@v2
with:
path: node_modules
key: node-modules-24-${{ hashFiles('package-lock.json') }}
key: node-modules-${{ hashFiles('package-lock.json') }}
- name: Install Node modules
if: steps.node-cache.outputs.cache-hit != 'true'
run: npm install
- name: Build Zotero
run: npm run build
# Currently necessary for document-worker Webpack: https://stackoverflow.com/a/69746937
- name: Upload deployment ZIP
if: |
env.ACT != 'true'
&& github.repository == 'zotero/zotero'
&& github.event_name == 'push'
&& (github.ref == 'refs/heads/master' || endsWith(github.ref, '-hotfix') || github.ref == 'refs/heads/gh-actions-ci-test')
env:
NODE_OPTIONS: --openssl-legacy-provider
# Create deployment ZIP from the build output, then replace build/ with the
# unzipped contents so that tests run against the same artifact that gets
# deployed. This catches problems that only manifest after a zip round-trip
# (e.g., resolved symlinks, missing files).
- name: Create deployment ZIP
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
run: |
mkdir build-zip
cd build
zip -r ../build.zip *
zip -r ../build-zip/$GITHUB_SHA.zip *
cd ..
- name: Replace build with ZIP contents
run: |
rm -rf build
mkdir build
cd build
unzip ../build.zip
- name: Set up SMB share
if: matrix.shard == 'smb'
timeout-minutes: 10
run: |
sudo apt install -y --no-install-recommends samba cifs-utils
sudo mkdir -p /srv/zotero-smb /mnt/zotero-smb
sudo chown $(whoami) /srv/zotero-smb
sudo tee -a /etc/samba/smb.conf > /dev/null <<EOF
[ztest]
path = /srv/zotero-smb
read only = no
EOF
(echo smbtestpass; echo smbtestpass) | sudo smbpasswd -s -a $(whoami)
sudo systemctl restart smbd
sudo mount -t cifs //127.0.0.1/ztest /mnt/zotero-smb \
-o user=$(whoami),pass=smbtestpass,vers=3.0,uid=$(id -u),gid=$(id -g)
- name: Set up NFS share
if: matrix.shard == 'nfs'
timeout-minutes: 10
run: |
sudo apt install -y --no-install-recommends nfs-kernel-server
sudo mkdir -p /srv/zotero-nfs /mnt/zotero-nfs
sudo chown $(whoami) /srv/zotero-nfs
echo "/srv/zotero-nfs localhost(rw,no_subtree_check,insecure)" | sudo tee -a /etc/exports
sudo exportfs -ra
sudo mount -t nfs4 localhost:/srv/zotero-nfs /mnt/zotero-nfs
sudo gem install --no-document dpl dpl-s3
dpl --provider=s3 --bucket=zotero-download --local-dir=build-zip --upload-dir=ci/client --acl=public-read --skip_cleanup=true
- name: Run tests
if: matrix.shard != 'smb' && matrix.shard != 'nfs'
run: xvfb-run test/runtests.sh -f -r 3 -p ${{ matrix.shard }}/4
# The step timeout turns a startup hang into a failure
- name: Run tests on network share
if: matrix.shard == 'smb' || matrix.shard == 'nfs'
timeout-minutes: 10
run: TMPDIR=/mnt/zotero-${{ matrix.shard }} xvfb-run test/runtests.sh -f -r 3 -b db file
# Run the db and file tests on macOS with the test data directory on a loopback NFS
# mount. On macOS, SQLite selects locking methods without shared-memory support on
# network filesystems, which is what the network-filesystem database handling has to
# detect and handle, so this runs the real code path that crashed on SMB/NFS/sshfs
# data directories.
test-mac:
name: Test (macOS NFS)
runs-on: macos-15
timeout-minutes: 30
needs: changes
if: >
needs.changes.outputs.network == 'true'
&& (github.event_name != 'pull_request'
|| github.event.pull_request.head.repo.full_name != github.repository)
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
lfs: true
- name: Install Node
uses: actions/setup-node@v4
with:
node-version: 24
- name: Cache xulrunner
id: xulrunner-cache
uses: actions/cache@v4
with:
path: app/xulrunner/Firefox.app
key: xulrunner-mac-${{ hashFiles('app/config.sh', 'app/scripts/fetch_xulrunner') }}
- name: Fetch xulrunner
if: steps.xulrunner-cache.outputs.cache-hit != 'true'
run: app/scripts/fetch_xulrunner -p m
- name: Cache Node modules
id: node-cache
uses: actions/cache@v4
with:
path: node_modules
key: node-modules-mac-24-${{ hashFiles('package-lock.json') }}
- name: Install Node modules
if: steps.node-cache.outputs.cache-hit != 'true'
run: npm install
- name: Build Zotero
run: npm run build
# Currently necessary for document-worker Webpack: https://stackoverflow.com/a/69746937
env:
NODE_OPTIONS: --openssl-legacy-provider
- name: Set up NFS share
run: |
sudo mkdir -p /private/var/zotero-nfs
sudo chown $(whoami) /private/var/zotero-nfs
echo "/private/var/zotero-nfs -mapall=$(whoami) localhost" | sudo tee /etc/exports
sudo nfsd enable || sudo nfsd start
sleep 2
showmount -e localhost
mkdir -p "$HOME/zotero-nfs"
sudo mount_nfs -o vers=3 localhost:/private/var/zotero-nfs "$HOME/zotero-nfs"
# The step timeout turns a startup hang into a failure
- name: Run tests on network share
timeout-minutes: 10
run: TMPDIR="$HOME/zotero-nfs" test/runtests.sh -f -r 3 -b db file
# Boot the Windows build -- which uses custom-built Firefox components (xul.dll) rather
# than stock Mozilla binaries -- and run the db and file tests. A Gecko bump commit
# updates the custom-component hashes in config.sh along with the version, so this
# tests each new set of custom components.
test-win:
name: Test (Windows ${{ matrix.arch }})
runs-on: ${{ matrix.os }}
timeout-minutes: 40
needs: changes
if: >
needs.changes.outputs.windows == 'true'
&& (github.event_name != 'pull_request'
|| github.event.pull_request.head.repo.full_name != github.repository)
strategy:
fail-fast: false
matrix:
include:
- arch: x64
os: windows-latest
- arch: arm64
os: windows-11-arm
defaults:
run:
shell: bash
steps:
# The repository contains symlinks, which Git checks out as plain files on Windows
# by default, breaking the build
- name: Enable symlinks
run: git config --global core.symlinks true
- uses: actions/checkout@v4
with:
submodules: recursive
lfs: true
- name: Install Node
uses: actions/setup-node@v4
with:
node-version: 24
# Git Bash has unzip but not zip, which fetch_xulrunner needs to repack omni.ja
- name: Install zip
run: choco install zip --no-progress -y
- name: Cache xulrunner
id: xulrunner-cache
uses: actions/cache@v4
with:
path: app/xulrunner/firefox-win-${{ matrix.arch }}
key: xulrunner-win-${{ matrix.arch }}-${{ hashFiles('app/config.sh', 'app/scripts/fetch_xulrunner') }}
- name: Fetch xulrunner
if: steps.xulrunner-cache.outputs.cache-hit != 'true'
run: app/scripts/fetch_xulrunner -p w -a ${{ matrix.arch }}
- name: Cache Node modules
id: node-cache
uses: actions/cache@v4
with:
path: node_modules
key: node-modules-win-24-${{ hashFiles('package-lock.json') }}
- name: Install Node modules
if: steps.node-cache.outputs.cache-hit != 'true'
run: npm install
# Committed symlinks point into node_modules, which doesn't exist at checkout time,
# so Git creates the directory ones with the wrong symlink type on Windows. Recreate
# them now that the targets exist.
- name: Recreate symlinks
run: |
git ls-files -s | awk '$1 == 120000 { print $4 }' | xargs rm
git checkout -- .
- name: Build Zotero
run: npm run build
# Currently necessary for document-worker Webpack: https://stackoverflow.com/a/69746937
env:
NODE_OPTIONS: --openssl-legacy-provider
# The step timeout turns a startup hang into a failure
- name: Run tests
timeout-minutes: 15
run: test/runtests.sh -f -r 3 -b -x app/staging/Zotero_win-${{ matrix.arch }}/zotero.exe db file
utilities:
name: Utilities Tests
runs-on: ubuntu-latest
if: >
github.event_name != 'pull_request'
|| github.event.pull_request.head.repo.full_name != github.repository
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
- name: Install Node
uses: actions/setup-node@v4
with:
node-version: 24
run: xvfb-run test/runtests.sh -x firefox-x86_64/firefox -f
- name: Cache utilities Node modules
id: utilities-node-cache
uses: actions/cache@v4
uses: actions/cache@v2
with:
path: chrome/content/zotero/xpcom/utilities/node_modules
key: utilities-node-modules-24-${{ hashFiles('chrome/content/zotero/xpcom/utilities/package-lock.json') }}
key: utilities-node-modules-${{ hashFiles('chrome/content/zotero/xpcom/utilities/package-lock.json') }}
- name: Install utilities Node modules
if: steps.utilities-node-cache.outputs.cache-hit != 'true'
@ -367,73 +88,3 @@ jobs:
- name: Run utilities tests
run: |
npm test --prefix chrome/content/zotero/xpcom/utilities -- -j resource/schema/global/schema.json
# Build deployment ZIPs from main, version branches (e.g., 9.0, 10.0), and *-hotfix branches
deploy:
name: Build, Upload
runs-on: ubuntu-latest
if: github.event_name == 'push' && github.repository == 'zotero/zotero'
steps:
- name: Check if deployment branch
id: check-deploy
if: env.ACT != 'true'
run: |
branch="${GITHUB_REF#refs/heads/}"
if [[ "$branch" == "main" || "$branch" =~ ^[0-9]+\.[0-9]+$ || "$branch" == *-hotfix ]]; then
echo "deploy=true" >> "$GITHUB_OUTPUT"
fi
- uses: actions/checkout@v4
if: steps.check-deploy.outputs.deploy == 'true'
with:
submodules: recursive
lfs: true
- name: Install Node
if: steps.check-deploy.outputs.deploy == 'true'
uses: actions/setup-node@v4
with:
node-version: 24
- name: Cache Node modules
id: node-cache
if: steps.check-deploy.outputs.deploy == 'true'
uses: actions/cache@v4
with:
path: node_modules
key: node-modules-24-${{ hashFiles('package-lock.json') }}
- name: Install Node modules
if: steps.check-deploy.outputs.deploy == 'true' && steps.node-cache.outputs.cache-hit != 'true'
run: npm install
- name: Build Zotero
if: steps.check-deploy.outputs.deploy == 'true'
run: npm run build
# Currently necessary for document-worker Webpack: https://stackoverflow.com/a/69746937
env:
NODE_OPTIONS: --openssl-legacy-provider
- name: Create deployment ZIP
if: steps.check-deploy.outputs.deploy == 'true'
run: |
cd build
zip -r ../build.zip *
cd ..
- uses: ruby/setup-ruby@v1
if: steps.check-deploy.outputs.deploy == 'true'
with:
ruby-version: '3.3'
bundler-cache: true # runs 'bundle install' and caches installed gems automatically
- name: Upload deployment ZIP
if: steps.check-deploy.outputs.deploy == 'true'
env:
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
run: |
mkdir build-zip
cp build.zip build-zip/$GITHUB_SHA.zip
gem install --no-document dpl -v '>= 2.0'
dpl s3 --bucket zotero-download --local_dir build-zip --upload_dir ci/client --acl public_read

3
.gitignore vendored
View file

@ -1,6 +1,5 @@
.DS_Store
node_modules
build/
build
.signatures.json
tmp
app/win/codesign

21
.gitmodules vendored
View file

@ -18,6 +18,10 @@
path = test/resource/mocha
url = https://github.com/mochajs/mocha.git
branch = master
[submodule "test/resource/chai-as-promised"]
path = test/resource/chai-as-promised
url = https://github.com/domenic/chai-as-promised.git
branch = master
[submodule "resource/schema/global"]
path = resource/schema/global
url = https://github.com/zotero/zotero-schema.git
@ -26,12 +30,12 @@
path = resource/SingleFile
url = https://github.com/gildas-lormeau/SingleFile.git
[submodule "pdf-reader"]
path = reader
url = https://github.com/zotero/reader.git
path = pdf-reader
url = https://github.com/zotero/pdf-reader.git
branch = master
[submodule "pdf-worker"]
path = document-worker
url = https://github.com/zotero/document-worker.git
path = pdf-worker
url = https://github.com/zotero/pdf-worker.git
branch = master
[submodule "note-editor"]
path = note-editor
@ -43,12 +47,3 @@
[submodule "chrome/content/zotero/xpcom/translate"]
path = chrome/content/zotero/xpcom/translate
url = https://github.com/zotero/translate.git
[submodule "app/modules/zotero-word-for-mac-integration"]
path = app/modules/zotero-word-for-mac-integration
url = https://github.com/zotero/zotero-word-for-mac-integration.git
[submodule "app/modules/zotero-word-for-windows-integration"]
path = app/modules/zotero-word-for-windows-integration
url = https://github.com/zotero/zotero-word-for-windows-integration.git
[submodule "app/modules/zotero-libreoffice-integration"]
path = app/modules/zotero-libreoffice-integration
url = https://github.com/zotero/zotero-libreoffice-integration.git

110
CLAUDE.md
View file

@ -1,110 +0,0 @@
# CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
## Project Overview
Zotero is a Firefox-based desktop research management application. It runs as a XUL/XHTML application on a Mozilla platform (not Electron, not a web app). The UI uses a mix of XUL/XHTML, custom elements (Web Components), and React components.
## Build & Development Commands
```bash
npm install # Install dependencies
npm run build # Full build (Babel transpile JS/JSX, compile SCSS, browserify, symlink)
npm run clean-build # Clean build output and rebuild
```
### Running Tests
Tests run inside a built Zotero application instance via `test/runtests.sh`:
```bash
test/runtests.sh # Run all tests
test/runtests.sh item # Run a single test file (omit "Test" and .js extension)
test/runtests.sh item collections # Run multiple test files
test/runtests.sh -g "pattern" # Run only tests matching a grep pattern
test/runtests.sh -f # Stop after first failure
test/runtests.sh -s item # Start at a specific test file
test/runtests.sh -e item # End at a specific test file
test/runtests.sh -c # Open JS console, don't quit on completion
test/runtests.sh -b # Skip bundled translator/style installation (for faster startup when not necessary)
test/runtests.sh -d 5 # Enable debug logging (level 1-5; default is 3)
```
Tests use Mocha + Chai (assert style) + Sinon. Test files live in `test/tests/` and follow the naming convention `<module>Test.js`. Test helpers are in `test/content/support.js`.
The test runner automatically triggers `npm run build` if the watch process isn't running, so it's not necessary to manually run a build before running tests.
Tips:
- Pass flags before test names (e.g., `test/runtests.sh -f item`).
- `-f` should almost always be used, since test failures can cause later spurious test failures.
- To view debug logging for a specific test when running multiple tests, add `Zotero.Debug.init(1)` at the beginning of the test and run with `-d 5`.
### Linting
```bash
npx eslint <file> # Lint a specific file
```
ESLint v9 flat config is in `eslint.config.mjs`. Uses `@zotero/eslint-config`, Babel parser, and React plugin. Currently, the code base is not fully linted, so only worry about issues with new or modified code lines.
## Architecture
### Core Layers
- **XPCOM modules** (`chrome/content/zotero/xpcom/`) -- Core business logic. Loaded sequentially by `chrome/content/zotero/zotero.mjs`. All modules attach to the global `Zotero` namespace (e.g., `Zotero.Items`, `Zotero.Sync.Runner`).
- **Data model** (`chrome/content/zotero/xpcom/data/`) -- ORM-like classes for database entities. `Zotero.DataObject` is the base class; `Zotero.Item`, `Zotero.Collection`, `Zotero.Search`, `Zotero.Library`, etc. extend it. Plural classes (`Zotero.Items`, `Zotero.Collections`) manage object caches and queries. Data objects use an async `saveTx()` pattern for persistence.
- **Database** (`chrome/content/zotero/xpcom/db.js`) -- SQLite via Mozilla's mozStorage API. Accessed through `Zotero.DB.queryAsync()`, `Zotero.DB.executeTransaction()`.
- **Sync system** (`chrome/content/zotero/xpcom/sync/`) -- `syncRunner.js` orchestrates sync. `syncEngine.js` handles object-level sync logic. `syncAPIClient.js` communicates with the Zotero API server. `syncLocal.js` manages local sync state. Similar `storage*` files for file syncing, along with zfs.js (Zotero Storage) and webdav.js (WebDAV).
- **HTTP server** (`chrome/content/zotero/xpcom/server/`) -- Local HTTP server for browser connector integration and local API.
### UI Layers
- **Main window**: `chrome/content/zotero/zoteroPane.xhtml` + `zoteroPane.js`
- **Custom elements** (`chrome/content/zotero/elements/`) -- XUL custom elements inheriting from `XULElementBase` (defined in `elements/base.js`), which provides lifecycle helpers (`init()`, `destroy()`, `content` getter for templates). Registered via `customElements.define()`.
- **React components** (`chrome/content/zotero/components/`) -- Used for complex interactive UI (tag selector, virtualized table, item tree, collection tree). Major tree views are `itemTree.jsx` and `collectionTree.jsx`.
- **SCSS styles** (`scss/`) -- Compiled to CSS. Platform-specific overrides in `scss/mac/`, `scss/win/`, `scss/linux/`.
- **Localization** -- Fluent (`.ftl` files) in `chrome/locale/en-US/zotero/`. Accessed via `data-l10n-id` attributes or `Zotero.getString()` for legacy `.properties` strings. All new strings must be added to `.ftl` files -- do not add new strings to `.properties` or `.dtd` files.
### Submodules
Several features are developed in separate repos and included as Git submodules:
- `reader/` -- PDF/EPUB/snapshot reader with annotations
- `note-editor/` -- Rich text note editor
- `document-worker/` -- PDF processing (extraction, manipulation)
- `translators/` -- 760+ web translators for importing metadata from websites
- `styles/` -- CSL citation styles
- `chrome/content/zotero/xpcom/utilities/` -- Shared utility library
- `chrome/content/zotero/xpcom/translate/` -- Translation framework
- `resource/SingleFile/` -- Web page archiving
### Build System (`js-build/`)
Custom Node.js build system (not Webpack). `js-build/config.js` defines what gets built:
- **JS/JSX files** in `chrome/`, `components/`, `defaults/`, `test/` are transpiled via Babel (React JSX, CommonJS modules)
- **SCSS files** in `scss/` and `chrome/skin/` are compiled with Dart Sass
- **Browserify** bundles select npm packages (react-select, sinon, url) for use in the XUL environment
- **Symlinks** connect source files and submodules into the `build/` directory
- The built app reads from `build/`, not directly from source
## Code Style
- Tabs for indentation, not spaces
- Use `let` instead of `const` except for true scalar constants (e.g., `const MAX_SECONDS = 5 * 60;`)
- No cuddled braces (opening brace on same line, but `else`/`catch`/etc. on their own line)
- Use two hyphens `--` in comments, not an em dash
- Indent blank lines to match surrounding indentation level
- Objects attach to the `Zotero` global namespace rather than using ES module exports
- Async code uses `async`/`await` throughout
- Mozilla/XPCOM APIs are available globally: `Cc`, `Ci`, `Cu`, `Cr`, `Services`, `ChromeUtils`, `IOUtils`, `PathUtils`
## Translators
See `translators/CLAUDE.md` for guidelines. Key rules: **never** generate translators from scratch, **never** generate UUIDs, **never** generate test cases -- all of these must be done through Zotero's Scaffold tool.

View file

@ -2,7 +2,7 @@
## Bug Reports and Feature Requests
Zotero does not use GitHub Issues for bug reports, feature requests, or support questions. Please post all such requests to the [Zotero Forums](https://forums.zotero.org), where Zotero developers and many others can help. See [How Zotero Support Works](https://www.zotero.org/support/zotero_support) for more information.
Zotero does not use GitHub Issues for bug reports or feature requests. Please post all such requests to the [Zotero Forums](https://forums.zotero.org), where Zotero developers and many others can help. See [How Zotero Support Works](https://www.zotero.org/support/zotero_support) for more information.
For confirmed bugs or agreed-upon changes, Zotero developers will create new issues in the relevant repositories.

View file

@ -6,4 +6,4 @@ Zotero
Please post feature requests or bug reports to the [Zotero Forums](https://forums.zotero.org/). If you're having trouble with Zotero, see [Getting Help](https://www.zotero.org/support/getting_help).
For more information on how to use this source code, see the [Zotero documentation](https://www.zotero.org/support/dev/source_code).
For more information on how to use this source code, see the [Zotero wiki](https://www.zotero.org/support/dev/source_code).

12
app/.gitignore vendored
View file

@ -1,12 +0,0 @@
*~
cache
config-custom.sh
dist
lastrev
staging
tmp
xulrunner
win/resource_hacker
win/firefox-*.win32.zip
win/firefox-*.win64.zip
win/firefox-*.win64-aarch64.zip

View file

@ -1,4 +0,0 @@
# Zotero Standalone build utility
These files are used to bundle the [Zotero core](https://github.com/zotero/zotero) into distributable bundles for Mac, Windows, and Linux.
Instructions for building and packaging are available on the [Zotero wiki](https://www.zotero.org/support/dev/client_coding/building_the_standalone_client).

View file

@ -1,18 +0,0 @@
[App]
Vendor=Zotero
Name=Zotero
Version={{VERSION}}
BuildID={{BUILDID}}
Copyright=Copyright (c) 2006-2025 Contributors
ID=zotero@zotero.org
[Gecko]
MinVersion=153.0
MaxVersion=153.99.*
[XRE]
EnableExtensionManager=1
EnableProfileMigrator=1
[AppUpdate]
URL=https://www.zotero.org/download/client/update/%VERSION%/%BUILD_ID%/%BUILD_TARGET%/%LOCALE%/%CHANNEL%/%OS_VERSION%/update.xml

View file

@ -1 +0,0 @@
<!ENTITY brandShortName "Zotero">

View file

@ -1,8 +0,0 @@
-brand-shorter-name = Zotero
-brand-short-name = Zotero
-brand-full-name = Zotero
-brand-product-name = Zotero
-vendor-short-name = Zotero
-app-name = Zotero
-subscription-name = Zotero Storage
trademarkInfo = Zotero is a trademark of the Corporation for Digital Scholarship.

View file

@ -1,3 +0,0 @@
brandShorterName=Zotero
brandShortName=Zotero
brandFullName=Zotero

View file

@ -1,3 +0,0 @@
locale branding en-US chrome/en-US/locale/branding/
content branding chrome/branding/content/
skin browser preferences chrome/skin/

View file

@ -1,104 +0,0 @@
let { CommandLineOptions, TestOptions } = ChromeUtils.importESModule("chrome://zotero/content/modules/commandLineOptions.mjs");
// Only allow BrowserContentHandler to open a new window if this is the initial launch,
// meaning our CLH isn't registered yet.
if (cmdLine.state != Ci.nsICommandLine.STATE_INITIAL_LAUNCH) {
cmdLine.preventDefault = true;
}
// Force debug output to window
if (cmdLine.handleFlag("ZoteroDebug", false)) {
CommandLineOptions.forceDebugLog = 2;
}
// Force debug output to text console
else if (cmdLine.handleFlag("ZoteroDebugText", false)) {
CommandLineOptions.forceDebugLog = 1;
}
// Pressing Ctrl-C via the terminal is interpreted as a crash, and after three crashes
// Firefox starts up in automatic safe mode (troubleshooting mode). To avoid this, we clear the crash
// counter when using one of the debug-logging flags, which generally imply terminal usage.
if (CommandLineOptions.forceDebugLog) {
Services.prefs.getBranch("toolkit.startup.").clearUserPref("recent_crashes");
}
CommandLineOptions.forceDataDir = cmdLine.handleFlagWithParam("datadir", false);
// Set here, to be acted upon in xpcom/commandLineHandler.js
CommandLineOptions.file = cmdLine.handleFlagWithParam("file", false);
CommandLineOptions.url = cmdLine.handleFlagWithParam("url", false);
if (CommandLineOptions.url) {
CommandLineOptions.url = cmdLine.resolveURI(CommandLineOptions.url);
}
var processTestOptions = false;
if (cmdLine.handleFlag("ZoteroTest", false)) {
CommandLineOptions.test = true;
processTestOptions = true;
}
if (cmdLine.handleFlag("ZoteroAutomatedTest", false)) {
CommandLineOptions.automatedTest = true;
}
if (cmdLine.handleFlag("ZoteroSkipBundledFiles", false)) {
CommandLineOptions.skipBundledFiles = true;
}
if (processTestOptions) {
TestOptions.tests = cmdLine.handleFlagWithParam("test", false);
TestOptions.noquit = cmdLine.handleFlag("noquit", false);
TestOptions.makeTestData = cmdLine.handleFlag("makeTestData", false);
TestOptions.noquit = !TestOptions.makeTestData && TestOptions.noquit;
TestOptions.runTests = !TestOptions.makeTestData;
TestOptions.bail = cmdLine.handleFlag("bail", false);
TestOptions.startAt = cmdLine.handleFlagWithParam("startAtTestFile", false);
TestOptions.stopAt = cmdLine.handleFlagWithParam("stopAtTestFile", false);
TestOptions.shard = cmdLine.handleFlagWithParam("shard", false);
TestOptions.grep = cmdLine.handleFlagWithParam("grep", false);
TestOptions.timeout = cmdLine.handleFlagWithParam("ZoteroTestTimeout", false);
TestOptions.retries = cmdLine.handleFlagWithParam("retries", false) || 0;
Services.ww.openWindow(
null,
"chrome://zotero-unit/content/runtests.html",
"_blank",
"chrome,dialog=no,all",
Cc["@mozilla.org/array;1"].createInstance(Ci.nsIMutableArray)
);
cmdLine.preventDefault = true;
}
if (cmdLine.handleFlag("debugger", false)) {
(async function () {
try {
let portOrPath = Services.prefs.getBranch('').getIntPref('devtools.debugger.remote-port');
const { DevToolsLoader } = ChromeUtils.importESModule(
"resource://devtools/shared/loader/Loader.sys.mjs"
);
const loader = new DevToolsLoader({
freshCompartment: true,
});
const { DevToolsServer } = loader.require("devtools/server/devtools-server");
const { SocketListener } = loader.require("devtools/shared/security/socket");
if (DevToolsServer.initialized) {
dump("Debugger server already initialized\n\n");
return;
}
DevToolsServer.init();
DevToolsServer.registerAllActors();
DevToolsServer.allowChromeProcess = true;
const socketOptions = { portOrPath };
const listener = new SocketListener(DevToolsServer, socketOptions);
await listener.open();
if (!DevToolsServer.listeningSockets) {
throw new Error("No listening sockets");
}
dump(`Debugger server started on ${portOrPath}\n\n`);
}
catch (e) {
dump(e + "\n\n");
Components.utils.reportError(e);
}
})();
}

View file

@ -1,242 +0,0 @@
/*
# -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
# ***** BEGIN LICENSE BLOCK *****
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
#
# The contents of this file are subject to the Mozilla Public License Version
# 1.1 (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
# http://www.mozilla.org/MPL/
#
# Software distributed under the License is distributed on an "AS IS" basis,
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
# for the specific language governing rights and limitations under the
# License.
#
# The Original Code is the Firefox Preferences System.
#
# The Initial Developer of the Original Code is
# Ben Goodger.
# Portions created by the Initial Developer are Copyright (C) 2005
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Ben Goodger <ben@mozilla.org>
# Kevin Gerich <webmail@kmgerich.com>
#
# Alternatively, the contents of this file may be used under the terms of
# either the GNU General Public License Version 2 or later (the "GPL"), or
# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
# in which case the provisions of the GPL or the LGPL are applicable instead
# of those above. If you wish to allow use of your version of this file only
# under the terms of either the GPL or the LGPL, and not to allow others to
# use your version of this file under the terms of the MPL, indicate your
# decision by deleting the provisions above and replace them with the notice
# and other provisions required by the GPL or the LGPL. If you do not delete
# the provisions above, a recipient may use your version of this file under
# the terms of any one of the MPL, the GPL or the LGPL.
#
# ***** END LICENSE BLOCK *****
*/
.windowDialog {
padding: 12px;
font: -moz-dialog;
}
.paneSelector {
list-style-image: url("chrome://browser/skin/preferences/Options.png");
}
/* ----- GENERAL BUTTON ----- */
radio[pane=paneGeneral],
radio[pane=paneMain] {
-moz-image-region: rect(0px, 32px, 32px, 0px);
}
/* ----- TABS BUTTON ----- */
radio[pane=paneTabs] {
-moz-image-region: rect(0px, 64px, 32px, 32px);
}
/* ----- CONTENT BUTTON ----- */
radio[pane=paneContent] {
-moz-image-region: rect(0px, 96px, 32px, 64px);
}
/* ----- APPLICATIONS BUTTON ----- */
radio[pane=paneApplications] {
-moz-image-region: rect(0px, 128px, 32px, 96px);
}
/* ----- PRIVACY BUTTON ----- */
radio[pane=panePrivacy] {
-moz-image-region: rect(0px, 160px, 32px, 128px);
}
/* ----- SECURITY BUTTON ----- */
radio[pane=paneSecurity] {
-moz-image-region: rect(0px, 192px, 32px, 160px);
}
/* ----- ADVANCED BUTTON ----- */
radio[pane=paneAdvanced] {
-moz-image-region: rect(0px, 224px, 32px, 192px);
}
/* ----- SYNC BUTTON ----- */
radio[pane=paneSync] {
list-style-image: url("chrome://browser/skin/preferences/Options-sync.png");
}
/* ----- APPLICATIONS PREFPANE ----- */
#BrowserPreferences[animated="true"] #handlersView {
height: 25em;
}
#BrowserPreferences[animated="false"] #handlersView {
-moz-box-flex: 1;
}
description {
font: small-caption;
font-weight: normal;
line-height: 1.3em;
margin-bottom: 4px !important;
}
prefpane .groupbox-body {
-moz-appearance: none;
padding: 8px 4px 4px 4px;
}
#paneTabs > groupbox {
margin: 0;
}
#tabPrefsBox {
margin: 12px 4px;
}
prefpane .groupbox-title {
background: url("chrome://global/skin/50pct_transparent_grey.png") repeat-x bottom left;
margin-bottom: 4px;
}
tabpanels {
padding: 20px 7px 7px;
}
caption {
-moz-padding-start: 5px;
padding-top: 4px;
padding-bottom: 2px;
}
#paneMain description,
#paneContent description,
#paneAdvanced description,
#paneSecurity description {
font: -moz-dialog;
}
#paneContent {
padding-top: 8px;
}
#paneContent row {
padding: 2px 4px;
-moz-box-align: center;
}
#popupPolicyRow,
#enableSoftwareInstallRow,
#enableImagesRow {
margin-bottom: 4px !important;
padding-bottom: 4px !important;
border-bottom: 1px solid #ccc;
}
#browserUseCurrent,
#browserUseBookmark,
#browserUseBlank {
margin-top: 10px;
}
#advancedPrefs {
margin: 0 8px;
}
#privacyPrefs {
padding: 0 4px;
}
#privacyPrefs > tabpanels {
padding: 18px 10px 10px;
}
#OCSPDialogPane {
font: message-box !important;
}
/**
* Privacy Pane
*/
/* styles for the link elements copied from .text-link in global.css */
.inline-link {
color: LinkText;
text-decoration: underline;
}
.inline-link:not(:focus) {
outline: 1px dotted transparent;
}
/**
* Update Preferences
*/
#autoInstallOptions {
-moz-margin-start: 20px;
}
.updateControls {
-moz-margin-start: 10px;
}
/**
* Clear Private Data
*/
#SanitizeDialogPane > groupbox {
margin-top: 0;
}
/* ----- SYNC PANE ----- */
#syncDesc {
padding: 0 8em;
}
#accountCaptionImage {
list-style-image: url("chrome://mozapps/skin/profile/profileicon.png");
}
#syncAddDeviceLabel {
margin-top: 1em;
margin-bottom: 1em;
}
#syncEnginesList {
height: 10em;
}

View file

@ -1 +0,0 @@
en-US,ar,bg-BG,br,ca-AD,cs-CZ,da-DK,de,el-GR,en-AU,en-CA,en-GB,en-NZ,es-ES,et-EE,eu-ES,fa,fi-FI,fr-FR,gl-ES,hu-HU,id-ID,is-IS,it-IT,ja-JP,km,ko-KR,lt-LT,nb-NO,nl-NL,pl-PL,pt-BR,pt-PT,ro-RO,ru-RU,sk-SK,sl-SI,sr-RS,sv-SE,ta,th-TH,tr-TR,uk-UA,vi-VN,zh-CN,zh-TW

View file

@ -1,172 +0,0 @@
// We only want a single window, I think
pref("toolkit.singletonWindowType", "navigator:browser");
// For debugging purposes, show errors in console by default
pref("javascript.options.showInConsole", true);
// Don't retrieve unrequested links when performing standalone translation
pref("network.prefetch-next", false);
// Don't make DNS requests for links in snapshots
pref("network.dns.disablePrefetch", true);
// Don't open TCP connection when clicking on a link in a snapshot
pref("network.http.speculative-parallel-limit", 0);
// Let operations run as long as necessary
pref("dom.max_chrome_script_run_time", 0);
pref("intl.locale.requested", '');
pref("intl.regional_prefs.use_os_locales", false);
// Fix error initializing login manager after this was changed in Firefox 57
// Could also disable this with MOZ_LOADER_SHARE_GLOBAL, supposedly
pref("jsloader.shareGlobal", false);
// Needed due to https://bugzilla.mozilla.org/show_bug.cgi?id=1181977
pref("browser.hiddenWindowChromeURL", "chrome://zotero/content/standalone/hiddenWindow.xhtml");
// Use basicViewer for opening new DOM windows from content (for TinyMCE)
pref("browser.chromeURL", "chrome://zotero/content/standalone/basicViewer.xhtml");
// We need these to get the save dialog working with contentAreaUtils.js
pref("browser.download.useDownloadDir", false);
pref("browser.download.manager.showWhenStarting", false);
pref("browser.download.folderList", 1);
// Don't show add-on selection dialog
pref("extensions.shownSelectionUI", true);
pref("extensions.autoDisableScope", 11);
pref("network.protocol-handler.expose-all", false);
pref("network.protocol-handler.expose.zotero", true);
pref("network.protocol-handler.expose.http", true);
pref("network.protocol-handler.expose.https", true);
// Never go offline
pref("offline.autoDetect", false);
pref("network.manage-offline-status", false);
// Without this, we will throw up dialogs if asked to translate strange pages
pref("browser.xul.error_pages.enabled", true);
// Without this, scripts may decide to open popups
pref("dom.disable_open_during_load", true);
// Don't show security warning. The "warn_viewing_mixed" warning just lets the user know that some
// page elements were loaded over an insecure connection. This doesn't matter if all we're doing is
// scraping the page, since we don't provide any information to the site.
pref("security.warn_viewing_mixed", false);
// Temporarily allow plugins to load their own scripts from jar:file: URIs with loadSubScript()
// without passing allowUnsafeURL (Mozilla bug 1974213). This will be disabled once plugins have
// had time to update.
pref("security.allow_unsafe_subscript_loads", true);
// We do need synchronous XHR
pref("network.xhr.block_sync_system_requests", false);
// Preferences for add-on discovery
pref("extensions.getAddons.cache.enabled", false);
//pref("extensions.getAddons.maxResults", 15);
//pref("extensions.getAddons.get.url", "https://services.addons.mozilla.org/%LOCALE%/%APP%/api/%API_VERSION%/search/guid:%IDS%?src=thunderbird&appOS=%OS%&appVersion=%VERSION%&tMain=%TIME_MAIN%&tFirstPaint=%TIME_FIRST_PAINT%&tSessionRestored=%TIME_SESSION_RESTORED%");
//pref("extensions.getAddons.search.browseURL", "https://addons.mozilla.org/%LOCALE%/%APP%/search?q=%TERMS%");
//pref("extensions.getAddons.search.url", "https://services.addons.mozilla.org/%LOCALE%/%APP%/api/%API_VERSION%/search/%TERMS%/all/%MAX_RESULTS%/%OS%/%VERSION%?src=thunderbird");
//pref("extensions.webservice.discoverURL", "https://www.zotero.org/support/plugins");
// Check Windows certificate store for custom CAs
pref("security.enterprise_roots.enabled", true);
// Disable add-on signature checking with unbranded Firefox build
pref("xpinstall.signatures.required", false);
// Allow legacy extensions (though this might not be necessary)
pref("extensions.legacy.enabled", true);
// Allow installing XPIs from any host
pref("xpinstall.whitelist.required", false);
// Allow installing XPIs when using a custom CA
pref("extensions.install.requireBuiltInCerts", false);
pref("extensions.update.requireBuiltInCerts", false);
// Don't connect to the Mozilla extensions blocklist
pref("extensions.blocklist.enabled", false);
// Avoid warning in console when opening Tools -> Add-ons
pref("extensions.getAddons.link.url", "");
// Disable places
pref("places.history.enabled", false);
// Probably not used, but prevent an error in the console
pref("app.support.baseURL", "https://www.zotero.org/support/");
// Disable Telemetry, Health Report, error reporting, and remote settings
pref("toolkit.telemetry.unified", false);
pref("toolkit.telemetry.enabled", false);
pref("datareporting.policy.dataSubmissionEnabled", false);
pref("toolkit.crashreporter.enabled", false);
pref("extensions.remoteSettings.disabled", true);
pref("extensions.update.url", "");
// Don't try to load the "Get Add-ons" tab on first load of Add-ons window
pref("extensions.ui.lastCategory", "addons://list/extension");
// Don't show "Using experimental APIs requires a privileged add-on" warning
pref("extensions.experiments.enabled", true);
// Not set on Windows in Firefox anymore since it's a per-installation pref,
// but we override that in fetch_xulrunner
pref("app.update.auto", true);
// URL user can browse to manually if for some reason all update installation
// attempts fail.
pref("app.update.url.manual", "https://www.zotero.org/download");
// A default value for the "More information about this update" link
// supplied in the "An update is available" page of the update wizard.
pref("app.update.url.details", "https://www.zotero.org/support/changelog");
// Interval: Time between checks for a new version (in seconds)
// default=1 day
pref("app.update.interval", 86400);
// The minimum delay in seconds for the timer to fire.
// default=2 minutes
pref("app.update.timerMinimumDelay", 120);
// Whether or not we show a dialog box informing the user that the update was
// successfully applied. This is off in Firefox by default since we show a
// upgrade start page instead! Other apps may wish to show this UI, and supply
// a whatsNewURL field in their brand.properties that contains a link to a page
// which tells users what's new in this new update.
// update channel for this build
pref("app.update.channel", "default");
// This should probably not be a preference that's used in toolkit....
pref("browser.preferences.instantApply", false);
// Allow elements to be displayed full-screen
pref("full-screen-api.enabled", true);
// Allow chrome access in DevTools
// This enables the input field in the Browser Console tool
pref("devtools.chrome.enabled", true);
// Default mousewheel action with Alt/Option is History Back/Forward in Firefox
// We don't have History navigation and users want to scroll the tree with Option
// key held down
pref("mousewheel.with_alt.action", 1);
// Use the system print dialog instead of the new tab-based print dialog in Firefox
pref("print.prefer_system_dialog", true);
// Disable libvpx decoding/encoding
pref("media.webm.enabled", false);
pref("media.encoder.webm.enabled", false);
pref("media.mediasource.webm.enabled", false);
pref("media.mediasource.webm.audio.enabled", false);
pref("media.mediasource.vp9.enabled", false);
pref("media.ffvpx.enabled", false);
pref("media.ffvpx.mp3.enabled", false);
pref("media.rdd-vpx.enabled", false);
pref("media.rdd-ffvpx.enabled", false);
pref("media.utility-ffvpx.enabled", false);
// Allow collectionTree scrolling when Control is highlighting collections on win
pref("mousewheel.with_control.action", 1);

View file

@ -1,188 +0,0 @@
%if 0
/*
# -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
# ***** BEGIN LICENSE BLOCK *****
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
#
# The contents of this file are subject to the Mozilla Public License Version
# 1.1 (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
# http://www.mozilla.org/MPL/
#
# Software distributed under the License is distributed on an "AS IS" basis,
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
# for the specific language governing rights and limitations under the
# License.
#
# The Original Code is the Firefox Preferences System.
#
# The Initial Developer of the Original Code is
# Ben Goodger.
# Portions created by the Initial Developer are Copyright (C) 2005
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Ben Goodger <ben@mozilla.org>
#
# Alternatively, the contents of this file may be used under the terms of
# either the GNU General Public License Version 2 or later (the "GPL"), or
# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
# in which case the provisions of the GPL or the LGPL are applicable instead
# of those above. If you wish to allow use of your version of this file only
# under the terms of either the GPL or the LGPL, and not to allow others to
# use your version of this file under the terms of the MPL, indicate your
# decision by deleting the provisions above and replace them with the notice
# and other provisions required by the GPL or the LGPL. If you do not delete
# the provisions above, a recipient may use your version of this file under
# the terms of any one of the MPL, the GPL or the LGPL.
#
# ***** END LICENSE BLOCK *****
*/
%endif
/* Global Styles */
#BrowserPreferences radio[pane] {
list-style-image: url("chrome://browser/skin/preferences/Options.png");
}
radio[pane=paneMain] {
-moz-image-region: rect(0px, 32px, 32px, 0px)
}
radio[pane=paneTabs] {
-moz-image-region: rect(0px, 64px, 32px, 32px)
}
radio[pane=paneContent] {
-moz-image-region: rect(0px, 96px, 32px, 64px)
}
radio[pane=paneApplications] {
-moz-image-region: rect(0px, 128px, 32px, 96px)
}
radio[pane=panePrivacy] {
-moz-image-region: rect(0px, 160px, 32px, 128px)
}
radio[pane=paneSecurity] {
-moz-image-region: rect(0px, 192px, 32px, 160px)
}
radio[pane=paneAdvanced] {
-moz-image-region: rect(0px, 224px, 32px, 192px)
}
%ifdef MOZ_SERVICES_SYNC
radio[pane=paneSync] {
list-style-image: url("chrome://browser/skin/preferences/Options-sync.png") !important;
}
%endif
/* Applications Pane */
#BrowserPreferences[animated="true"] #handlersView {
height: 25em;
}
#BrowserPreferences[animated="false"] #handlersView {
-moz-box-flex: 1;
}
/* Privacy Pane */
/* styles for the link elements copied from .text-link in global.css */
.inline-link {
color: LinkText;
text-decoration: underline;
}
.inline-link:not(:focus) {
outline: 1px dotted transparent;
}
/* Modeless Window Dialogs */
.windowDialog,
.windowDialog prefpane {
padding: 0px;
}
.contentPane {
margin: 9px 8px 5px 8px;
}
.actionButtons {
margin: 0px 3px 6px 3px !important;
}
/* Cookies Manager */
#cookiesChildren::-moz-tree-image(domainCol) {
width: 16px;
height: 16px;
margin: 0px 2px;
list-style-image: url("chrome://mozapps/skin/places/defaultFavicon.png");
}
#paneApplications {
margin-left: 4px;
margin-right: 4px;
padding-left: 0;
padding-right: 0;
}
#linksOpenInBox {
margin-top: 5px;
}
#paneAdvanced {
padding-bottom: 10px;
}
#advancedPrefs {
margin-left: 0;
margin-right: 0;
}
#cookiesChildren::-moz-tree-image(domainCol, container) {
list-style-image: url("moz-icon://stock/gtk-directory?size=menu");
}
#cookieInfoBox {
border: 1px solid ThreeDShadow;
border-radius: 0px;
margin: 4px;
padding: 0px;
}
/* bottom-most box containing a groupbox in a prefpane. Prevents the bottom
of the groupbox from being cutoff */
.bottomBox {
padding-bottom: 4px;
}
/**
* Clear Private Data
*/
#SanitizeDialogPane > groupbox {
margin-top: 0;
}
%ifdef MOZ_SERVICES_SYNC
/* Sync Pane */
#syncDesc {
padding: 0 8em;
}
#accountCaptionImage {
list-style-image: url("chrome://mozapps/skin/profile/profileicon.png");
}
#syncAddDeviceLabel {
margin-top: 1em;
margin-bottom: 1em;
}
#syncEnginesList {
height: 10em;
}
%endif

View file

@ -1,4 +0,0 @@
; This file is in the UTF-8 encoding
[Strings]
Title=Zotero Update
Info=Zotero is installing your updates and will start in a few moments…

View file

@ -1,178 +0,0 @@
/*
# -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
# ***** BEGIN LICENSE BLOCK *****
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
#
# The contents of this file are subject to the Mozilla Public License Version
# 1.1 (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
# http://www.mozilla.org/MPL/
#
# Software distributed under the License is distributed on an "AS IS" basis,
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
# for the specific language governing rights and limitations under the
# License.
#
# The Original Code is the Firefox Preferences System.
#
# The Initial Developer of the Original Code is
# Ben Goodger.
# Portions created by the Initial Developer are Copyright (C) 2005
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Ben Goodger <ben@mozilla.org>
#
# Alternatively, the contents of this file may be used under the terms of
# either the GNU General Public License Version 2 or later (the "GPL"), or
# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
# in which case the provisions of the GPL or the LGPL are applicable instead
# of those above. If you wish to allow use of your version of this file only
# under the terms of either the GPL or the LGPL, and not to allow others to
# use your version of this file under the terms of the MPL, indicate your
# decision by deleting the provisions above and replace them with the notice
# and other provisions required by the GPL or the LGPL. If you do not delete
# the provisions above, a recipient may use your version of this file under
# the terms of any one of the MPL, the GPL or the LGPL.
#
# ***** END LICENSE BLOCK *****
*/
/* Global Styles */
#BrowserPreferences radio[pane] {
list-style-image: url("chrome://browser/skin/preferences/Options.png");
padding: 5px 3px 1px;
}
radio[pane=paneMain] {
-moz-image-region: rect(0, 32px, 32px, 0);
}
radio[pane=paneTabs] {
-moz-image-region: rect(0, 64px, 32px, 32px);
}
radio[pane=paneContent] {
-moz-image-region: rect(0, 96px, 32px, 64px);
}
radio[pane=paneApplications] {
-moz-image-region: rect(0, 128px, 32px, 96px);
}
radio[pane=panePrivacy] {
-moz-image-region: rect(0, 160px, 32px, 128px);
}
radio[pane=paneSecurity] {
-moz-image-region: rect(0, 192px, 32px, 160px);
}
radio[pane=paneAdvanced] {
-moz-image-region: rect(0, 224px, 32px, 192px);
}
%ifdef MOZ_SERVICES_SYNC
radio[pane=paneSync] {
list-style-image: url("chrome://browser/skin/preferences/Options-sync.png") !important;
}
%endif
/* Applications Pane */
#BrowserPreferences[animated="true"] #handlersView {
height: 25em;
}
#BrowserPreferences[animated="false"] #handlersView {
-moz-box-flex: 1;
}
/* Privacy Pane */
/* styles for the link elements copied from .text-link in global.css */
.inline-link {
color: LinkText;
text-decoration: underline;
}
.inline-link:not(:focus) {
outline: 1px dotted transparent;
}
/* Modeless Window Dialogs */
.windowDialog,
.windowDialog prefpane {
padding: 0;
}
.contentPane {
margin: 9px 8px 5px;
}
.actionButtons {
margin: 0 3px 6px !important;
}
/* Cookies Manager */
#cookiesChildren::-moz-tree-image(domainCol) {
width: 16px;
height: 16px;
margin: 0 2px;
list-style-image: url("chrome://mozapps/skin/places/defaultFavicon.png") !important;
}
#cookiesChildren::-moz-tree-image(domainCol, container) {
list-style-image: url("chrome://global/skin/icons/folder-item.png") !important;
-moz-image-region: rect(0, 32px, 16px, 16px);
}
#cookiesChildren::-moz-tree-image(domainCol, container, open) {
-moz-image-region: rect(16px, 32px, 32px, 16px);
}
#cookieInfoBox {
border: 1px solid ThreeDShadow;
border-radius: 0;
margin: 4px;
padding: 0;
}
/* Advanced Pane */
/* Adding padding-bottom prevents the bottom of the tabpanel from being cutoff
when browser.preferences.animateFadeIn = true */
#advancedPrefs {
padding-bottom: 8px;
}
/* bottom-most box containing a groupbox in a prefpane. Prevents the bottom
of the groupbox from being cutoff */
.bottomBox {
padding-bottom: 4px;
}
%ifdef MOZ_SERVICES_SYNC
/* Sync Pane */
#syncDesc {
padding: 0 8em;
}
.syncGroupBox {
padding: 10px;
}
#accountCaptionImage {
list-style-image: url("chrome://mozapps/skin/profile/profileicon.png");
}
#syncAddDeviceLabel {
margin-top: 1em;
margin-bottom: 1em;
}
#syncEnginesList {
height: 11em;
}
%endif

File diff suppressed because it is too large Load diff

View file

@ -1,73 +0,0 @@
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
# Version of Gecko to build with
GECKO_VERSION_MAC="153.3.0esr"
GECKO_VERSION_LINUX="153.3.0esr"
GECKO_VERSION_WIN="153.3.0esr"
RUST_VERSION=1.94.0
# URL prefix for custom builds of Firefox components
custom_components_url="https://download.zotero.org/dev/firefox-components/"
custom_components_hash_mac="6b586ed383a480fed9d9786ad18a6e6d90b140739e5e4491096df291ec887571"
custom_components_hash_win_x64="db7c9556bd0f9e36120069391ce66cc199ed1ec4e2fdd3b931f71e35b4586d2b"
custom_components_hash_win_arm64="fd0f44b38a471009ce1cdd926f7f48be43ed773dad350c62383b8a7235da8711"
custom_components_hash_win32="694944349fdfd91296f272a68ac5d03183f02d47fdaa7ba9f2b1c74747652aa2"
APP_NAME="Zotero"
APP_ID="zotero\@zotero.org"
# Whether to sign builds
SIGN=0
# OS X Developer ID certificate information
DEVELOPER_ID=F0F1FE48DB909B263AC51C8215374D87FDC12121
# Keychain and keychain password, if not building via the GUI
KEYCHAIN=""
KEYCHAIN_PASSWORD=""
NOTARIZATION_BUNDLE_ID=""
NOTARIZATION_USER=""
NOTARIZATION_TEAM_ID=""
NOTARIZATION_PASSWORD=""
# Name of a notarytool keychain profile (see `xcrun notarytool store-credentials`), e.g., for an
# App Store Connect API key -- used instead of the Apple ID settings above if set
NOTARIZATION_PROFILE=""
# Paths for Windows installer build
NSIS_DIR='C:\Program Files (x86)\NSIS\'
SIGNTOOL_DELAY=5
# Directory for unpacked binaries
STAGE_DIR="$DIR/staging"
# Directory for packed binaries
DIST_DIR="$DIR/dist"
SOURCE_REPO_URL="https://github.com/zotero/zotero"
S3_BUCKET="zotero-download"
S3_CI_ZIP_PATH="ci/client"
S3_DIST_PATH="client"
DEPLOY_HOST="deploy.zotero"
DEPLOY_PATH="www/www-production/public/download/client"
BUILD_PLATFORMS=""
NUM_INCREMENTALS=6
if [ "`uname`" = "Darwin" ]; then
shopt -s expand_aliases
fi
if [ "`uname -o 2> /dev/null`" = "Cygwin" ]; then
export WIN_NATIVE=1
else
export WIN_NATIVE=0
fi
# Make utilities (mar/mbsdiff) available in the path
PATH="$DIR/xulrunner/bin:$PATH"
if [ -f "$DIR/config-custom.sh" ]; then
. "$DIR/config-custom.sh"
fi
unset DIR

View file

@ -1,44 +0,0 @@
#!/bin/bash
set -euo pipefail
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
APP_ROOT_DIR="$(dirname "$SCRIPT_DIR")"
. "$APP_ROOT_DIR/config.sh"
if [ -z "${1:-}" ]; then
echo "Usage: $0 x64|arm64" >&2
exit 1
fi
gecko_path=~/src/firefox
arch=$1
if [ ! -d "$gecko_path" ]; then
echo "$gecko_path is not a directory" >&2
exit 1
fi
# Install required Rust version
rustup toolchain install $RUST_VERSION
if [ $arch = "x64" ]; then
rust_target=x86_64
elif [ $arch = "arm64" ]; then
rust_target=aarch64
else
echo "Unknown architecture $arch" >&2
exit 1
fi
rustup target add $rust_target-unknown-linux-gnu
rm "$gecko_path/mozconfig"
touch "$gecko_path/mozconfig"
if [ $arch == "arm64" ]; then
echo "ac_add_options --target=aarch64-linux-gnu" >> "$gecko_path/mozconfig"
fi
cat "$SCRIPT_DIR/mozconfig" >> "$gecko_path/mozconfig"
cd "$gecko_path"
./mach build
./mach package

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.5 KiB

View file

@ -1,3 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
<polygon style="fill: #000000" points="13.863 2.73 13.027 1 2.137 1 2.137 3.8 2.137 3.921 8.822 3.921 1.289 13.233 2.137 15 13.863 15 13.863 12.142 13.863 12.021 6.448 12.021 13.863 2.73"/>
</svg>

Before

Width:  |  Height:  |  Size: 283 B

View file

@ -1,25 +0,0 @@
ac_add_options --enable-bootstrap
mk_add_options AUTOCLOBBER=1
# These don't all affect the stub, but they can't hurt, and we'll want them if
# we switch to custom XUL builds
ac_add_options MOZ_ENABLE_JS_DUMP=1
ac_add_options MOZ_ENABLE_FORKSERVER=
ac_add_options MOZ_TELEMETRY_REPORTING=
ac_add_options MOZ_DATA_REPORTING=
ac_add_options --disable-tests
ac_add_options --disable-debug
ac_add_options --disable-debug-symbols
ac_add_options --disable-webrtc
# This causes aarch64 build of 140.0esr to fail
#ac_add_options --disable-eme
export MOZILLA_OFFICIAL=1
export RELEASE_OR_BETA=1
MOZ_REQUIRE_SIGNING=
ac_add_options --enable-official-branding
# Build updater without MAR signature verification
ac_add_options --enable-unverified-updates

View file

@ -1,13 +0,0 @@
#!/bin/bash -e
#
# Run this to update the launcher file with the current path to the application icon
#
APPDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
if [ -w "$APPDIR"/zotero.desktop ]; then
sed -i -e "s@^Icon=.*@Icon=$APPDIR/icons/icon128.png@" "$APPDIR"/zotero.desktop
else
echo "$APPDIR"/zotero.desktop is not writable
exit 1
fi

View file

@ -1,43 +0,0 @@
#!/bin/bash
set -euo pipefail
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
cd "$SCRIPT_DIR"
if [ $# -ne 1 ]; then
echo "Usage: $0 <firefox-version>"
exit 1
fi
version="$1"
for arch in x86_64 aarch64; do
package="firefox-${version}.en-US.linux-${arch}.tar.xz"
if [ $arch = 'aarch64' ]; then
arch="arm64"
fi
if [ ! -f "$package" ]; then
echo "Error: Package not found: $package"
exit 1
fi
echo "Extracting updater from $package..."
tar --extract --xz --file="$package" --to-stdout "firefox/updater" > "updater-$arch"
# Add missing RUNPATH to custom fx140 builds, which is missing for unclear reasons.
# Without this, the updater fails looking for libmozsqlite3.so.
patchelf --set-rpath '$ORIGIN' "updater-$arch"
done
echo "Creating updater.tar.xz..."
if [ `uname` = "Darwin" ]; then
tar=gtar
else
tar=tar
fi
$tar --owner=0 --group=0 --numeric-owner --no-xattrs --mode=0755 -cJvf updater.tar.xz updater-x86_64 updater-arm64
rm updater-x86_64 updater-arm64
echo "Done: updater.tar.xz created"

View file

@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:a1f368bb36408d61d4b8f9dda561738686e626513346e138d55a0ef58055a6fc
size 123776

View file

@ -1,20 +0,0 @@
#!/bin/bash
# Increase open files limit
#
# Mozilla file functions (OS.File.move()/copy(), NetUtil.asyncFetch/asyncCopy()) can leave file
# descriptors open for a few seconds (even with an explicit inputStream.close() in the case of
# the latter), so a source installation that copies ~500 translators and styles (with fds for
# source and target) can exceed the default 1024 limit.
# Current hard-limit on Ubuntu 16.10 is 4096
ulimit -n 4096
# Allow profile downgrade for Zotero
export MOZ_ALLOW_DOWNGRADE=1
# Don't create dedicated profile (default-esr)
export MOZ_LEGACY_PROFILES=1
# Use wayland backend when available
export MOZ_ENABLE_WAYLAND=1
CALLDIR="$(dirname "$(readlink -f "$0")")"
"$CALLDIR/zotero-bin" -app "$CALLDIR/app/application.ini" "$@"

View file

@ -1,9 +0,0 @@
[Desktop Entry]
Name=Zotero
Exec=bash -c "$(dirname $(realpath $(echo %k | sed -e 's/^file:\\/\\///')))/zotero -url %U"
Icon=zotero.ico
Type=Application
Terminal=false
Categories=Office;
MimeType=text/plain;x-scheme-handler/zotero;application/x-research-info-systems;text/x-research-info-systems;text/ris;application/x-endnote-refer;application/x-inst-for-Scientific-info;application/mods+xml;application/rdf+xml;application/x-bibtex;text/x-bibtex;application/marc;application/vnd.citationstyles.style+xml
X-GNOME-SingleWindow=true

View file

@ -1,204 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>English</string>
<key>CFBundleDocumentTypes</key>
<array>
<!-- Import formats -->
<dict>
<key>CFBundleTypeExtensions</key>
<array>
<string>ris</string>
</array>
<!--<key>CFBundleTypeIconFile</key>
<string>document.icns</string>-->
<key>CFBundleTypeMIMETypes</key>
<array>
<string>application/x-research-info-systems</string>
<string>text/x-research-info-systems</string>
<string>text/ris</string>
<string>ris</string>
<string>application/x-endnote-refer</string>
</array>
<key>CFBundleTypeName</key>
<string>Research Information Systems Document</string>
<key>CFBundleTypeRole</key>
<string>Viewer</string>
</dict>
<dict>
<key>CFBundleTypeExtensions</key>
<array>
<string>ciw</string>
<string>isi</string>
</array>
<!--<key>CFBundleTypeIconFile</key>
<string>document.icns</string>-->
<key>CFBundleTypeMIMETypes</key>
<array>
<string>application/x-inst-for-Scientific-info</string>
</array>
<key>CFBundleTypeName</key>
<string>ISI Common Export Format Document</string>
<key>CFBundleTypeRole</key>
<string>Viewer</string>
</dict>
<dict>
<key>CFBundleTypeExtensions</key>
<array>
<string>mods</string>
</array>
<!--<key>CFBundleTypeIconFile</key>
<string>document.icns</string>-->
<key>CFBundleTypeMIMETypes</key>
<array>
<string>application/mods+xml</string>
</array>
<key>CFBundleTypeName</key>
<string>Metadata Object Description Schema Document</string>
<key>CFBundleTypeRole</key>
<string>Viewer</string>
</dict>
<dict>
<key>CFBundleTypeExtensions</key>
<array>
<string>rdf</string>
</array>
<!--<key>CFBundleTypeIconFile</key>
<string>document.icns</string>-->
<key>CFBundleTypeMIMETypes</key>
<array>
<string>application/rdf+xml</string>
</array>
<key>CFBundleTypeName</key>
<string>Resource Description Framework Document</string>
<key>CFBundleTypeRole</key>
<string>Viewer</string>
</dict>
<dict>
<key>CFBundleTypeExtensions</key>
<array>
<string>bib</string>
<string>bibtex</string>
</array>
<!--<key>CFBundleTypeIconFile</key>
<string>document.icns</string>-->
<key>CFBundleTypeMIMETypes</key>
<array>
<string>application/x-bibtex</string>
<string>text/x-bibtex</string>
</array>
<key>CFBundleTypeName</key>
<string>BibTeX Document</string>
<key>CFBundleTypeRole</key>
<string>Viewer</string>
</dict>
<dict>
<key>CFBundleTypeExtensions</key>
<array>
<string>mrc</string>
<string>marc</string>
</array>
<!--<key>CFBundleTypeIconFile</key>
<string>document.icns</string>-->
<key>CFBundleTypeMIMETypes</key>
<array>
<string>application/marc</string>
</array>
<key>CFBundleTypeName</key>
<string>MARC Document</string>
<key>CFBundleTypeRole</key>
<string>Viewer</string>
</dict>
<!-- Citation styles -->
<dict>
<key>CFBundleTypeExtensions</key>
<array>
<string>csl</string>
<string>csl.txt</string>
</array>
<!--<key>CFBundleTypeIconFile</key>
<string>document.icns</string>-->
<key>CFBundleTypeMIMETypes</key>
<array>
<string>application/vnd.citationstyles.style+xml</string>
</array>
<key>CFBundleTypeName</key>
<string>CSL Citation Style</string>
<key>CFBundleTypeRole</key>
<string>Viewer</string>
</dict>
<!-- Hopefully, we don't become the default app for these -->
<dict>
<key>CFBundleTypeExtensions</key>
<array>
<string>xml</string>
</array>
<!--<key>CFBundleTypeIconFile</key>
<string>document.icns</string>-->
<key>CFBundleTypeName</key>
<string>XML Document</string>
<key>CFBundleTypeRole</key>
<string>Viewer</string>
</dict>
<dict>
<key>CFBundleTypeExtensions</key>
<array>
<string>txt</string>
</array>
<!--<key>CFBundleTypeIconFile</key>
<string>document.icns</string>-->
<key>CFBundleTypeName</key>
<string>Text File</string>
<key>CFBundleTypeRole</key>
<string>Viewer</string>
</dict>
</array>
<key>CFBundleExecutable</key>
<string>zotero</string>
<key>CFBundleGetInfoString</key>
<string>Zotero {{VERSION}}, © 2006-2018 Contributors</string>
<key>CFBundleIconName</key>
<string>AppIcon</string>
<key>CFBundleIdentifier</key>
<string>org.zotero.zotero</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>Zotero</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>{{VERSION_NUMERIC}}</string>
<key>CFBundleSignature</key>
<string>ZOTR</string>
<key>CFBundleURLTypes</key>
<array>
<dict>
<!--<key>CFBundleURLIconFile</key>
<string>document.icns</string>-->
<key>CFBundleURLName</key>
<string>zotero URL</string>
<key>CFBundleURLSchemes</key>
<array>
<string>zotero</string>
</array>
</dict>
</array>
<key>CFBundleVersion</key>
<string>{{VERSION_NUMERIC}}</string>
<key>NSAppleScriptEnabled</key>
<true/>
<key>CGDisableCoalescedUpdates</key>
<true/>
<key>NSHighResolutionCapable</key>
<true/>
<key>NSSupportsAutomaticGraphicsSwitching</key>
<true/>
<key>LSMinimumSystemVersion</key>
<string>10.9.0</string>
</dict>
</plist>

View file

@ -1 +0,0 @@
APPLZOTR

Binary file not shown.

View file

@ -1,93 +0,0 @@
#!/bin/bash
set -e
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
APP_ROOT_DIR="$(dirname "$SCRIPT_DIR")"
. "$APP_ROOT_DIR/config.sh"
fx_app_name=Firefox.app
# Get Mozilla source directory from command line
if [ -z "${1:-}" ]; then
echo "Usage: $0 /path/to/firefox" >&2
exit 1
fi
GECKO_PATH="$(cd "$1" && pwd)"
mach=$GECKO_PATH/mach
BUILD_DIR=`mktemp -d`
function cleanup {
rm -rf $BUILD_DIR
}
trap cleanup EXIT
set -x
export MOZ_BUILD_DATE=`date "+%Y%m%d%H%M%S"`
# Install required Rust version
rustup toolchain install $RUST_VERSION
rustup target add --toolchain $RUST_VERSION aarch64-apple-darwin x86_64-apple-darwin
rustup default $RUST_VERSION
cp "$SCRIPT_DIR/mozconfig" "$GECKO_PATH"
# Build Firefox for Intel and Apple Silicon
export Z_ARCH=x64
$mach build
$mach package
export Z_ARCH=aarch64
$mach build
$mach package
cd $BUILD_DIR
# Unify into Universal build
# From https://searchfox.org/mozilla-central/rev/97c902e8f92b15dc63eb584bfc594ecb041242a4/taskcluster/scripts/misc/unify.sh
for i in x86_64 aarch64; do
$mach python -m mozbuild.action.unpack_dmg "$GECKO_PATH"/obj-$i-apple-darwin/dist/*.dmg $i
done
mv x86_64 x64
$mach python "$GECKO_PATH/toolkit/mozapps/installer/unify.py" x64/*.app aarch64/*.app
cp x64/$fx_app_name/Contents/MacOS/firefox zotero
xz zotero
mv zotero.xz "$APP_ROOT_DIR/mac/zotero.xz"
# Package custom Firefox components for fetch_xulrunner. Add XUL to this list if needed.
# Upload the archive to ${custom_components_url}mac/ and set custom_components_hash_mac
# in config.sh to the hash printed below.
custom_components=(libmozglue.dylib)
mkdir MacOS
for component in "${custom_components[@]}"; do
cp "x64/$fx_app_name/Contents/MacOS/$component" MacOS/
done
tar cfJ MacOS.tar.xz MacOS
components_hash=$(shasum -a 256 MacOS.tar.xz | cut -d ' ' -f 1)
components_file="$APP_ROOT_DIR/mac/$components_hash.tar.xz"
mv MacOS.tar.xz "$components_file"
echo "Custom Firefox components: $components_file"
echo "custom_components_hash_mac=\"$components_hash\""
# Save a copy of ChannelPrefs.framework
#
# Frameworks need to be signed, and we can't sign source builds, so store a signed copy with
# 'default' replaced with 'source'. Deployed builds will then replace 'source' with
# 'release'/'beta'/'dev'.
rm -rf "$APP_ROOT_DIR/mac/ChannelPrefs.framework"
cp -R x64/$fx_app_name/Contents/Frameworks/ChannelPrefs.framework "$APP_ROOT_DIR/mac/ChannelPrefs.framework"
pushd "$APP_ROOT_DIR/mac"
./set-channel-prefs-channel ChannelPrefs.framework/ChannelPrefs default source
security -v unlock-keychain -p "$KEYCHAIN_PASSWORD" ~/Library/Keychains/$KEYCHAIN.keychain-db
/usr/bin/codesign --force --options runtime --sign "$DEVELOPER_ID" ChannelPrefs.framework
/usr/bin/codesign -vvvv ChannelPrefs.framework
tar cfvJ ChannelPrefs.framework.tar.xz ChannelPrefs.framework
rm -rf ChannelPrefs.framework
popd
# Uncomment to build updater
#cd x64/$fx_app_name/Contents/MacOS/
#"$APP_ROOT_DIR/mac/updater_renamer"
#cat updater.app/Contents/Resources/English.lproj/InfoPlist.strings
#tar cfvJ "$APP_ROOT_DIR/mac/updater.tar.xz" updater.app/

View file

@ -1,34 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<!--
Entitlements to apply during codesigning of production builds.
-->
<plist version="1.0">
<dict>
<!-- Firefox needs to create executable pages (without MAP_JIT) -->
<key>com.apple.security.cs.allow-unsigned-executable-memory</key><true/>
<!-- Allow loading third party libraries. Needed for Flash and CDMs -->
<!-- Disabled for Zotero -->
<key>com.apple.security.cs.disable-library-validation</key><false/>
<!-- Firefox needs to access the microphone on sites the user allows -->
<!-- Disabled for Zotero -->
<key>com.apple.security.device.audio-input</key><false/>
<!-- Firefox needs to access the camera on sites the user allows -->
<!-- Disabled for Zotero -->
<key>com.apple.security.device.camera</key><false/>
<!-- Firefox needs to access the location on sites the user allows -->
<!-- Disabled for Zotero -->
<key>com.apple.security.personal-information.location</key><false/>
<!-- For SmartCardServices(7) -->
<!-- Disabled for Zotero -->
<key>com.apple.security.smartcard</key><false/>
<!-- Added for Zotero to control Word and bring windows to the front -->
<key>com.apple.security.automation.apple-events</key><true/>
</dict>
</plist>

View file

@ -1,35 +0,0 @@
if [ "$Z_ARCH" == "x64" ]; then
ac_add_options --target=x86_64-apple-darwin
elif [ "$Z_ARCH" == "aarch64" ]; then
ac_add_options --target=aarch64-apple-darwin
fi
ac_add_options --enable-bootstrap
ac_add_options --with-macos-sdk=$HOME/src/MacOSX26.5.sdk
mk_add_options AUTOCLOBBER=1
# These don't all affect the stub, but they can't hurt, and we'll want them if
# we switch to custom XUL builds
ac_add_options MOZ_ENABLE_JS_DUMP=1
ac_add_options MOZ_ENABLE_FORKSERVER=
ac_add_options MOZ_TELEMETRY_REPORTING=
ac_add_options MOZ_DATA_REPORTING=
ac_add_options --disable-tests
ac_add_options --disable-debug
ac_add_options --disable-debug-symbols
ac_add_options --disable-webrtc
ac_add_options --disable-eme
export MOZILLA_OFFICIAL=1
export RELEASE_OR_BETA=1
MOZ_REQUIRE_SIGNING=
# Official builds require source info, which Mozilla only detects automatically from
# Mercurial checkouts
export MOZ_SOURCE_REPO=https://github.com/mozilla-firefox/firefox
export MOZ_SOURCE_CHANGESET=$(git -C "$topsrcdir" rev-parse HEAD)
ac_add_options --enable-official-branding
# Build updater without MAR signature verification
ac_add_options --enable-unverified-updates

File diff suppressed because it is too large Load diff

View file

@ -1,242 +0,0 @@
diff --git a/browser/app/nsBrowserApp.cpp b/browser/app/nsBrowserApp.cpp
--- a/browser/app/nsBrowserApp.cpp
+++ b/browser/app/nsBrowserApp.cpp
@@ -193,19 +193,31 @@ static bool HasFlag(int argc, char* argv[], const char* s) {
}
return false;
}
#endif
constinit Bootstrap::UniquePtr gBootstrap;
static int do_main(int argc, char* argv[], char* envp[]) {
+ // Allow profile downgrade for Zotero
+ setenv("MOZ_ALLOW_DOWNGRADE", "1", 1);
+ // Don't create dedicated profile (default-esr)
+ setenv("MOZ_LEGACY_PROFILES", "1", 1);
+
// Allow firefox.exe to launch XULRunner apps via -app <application.ini>
// Note that -app must be the *first* argument.
- const char* appDataFile = getenv("XUL_APP_FILE");
+ UniqueFreePtr<char> iniPath = BinaryPath::GetApplicationIni();
+ if (!iniPath) {
+ Output("Couldn't find application.ini.\n");
+ return 255;
+ }
+ char *appDataFile = iniPath.get();
+
+
if ((!appDataFile || !*appDataFile) && (argc > 1 && IsFlag(argv[1], "app"))) {
if (argc == 2) {
Output("Incorrect number of arguments passed to -app");
return 255;
}
appDataFile = argv[2];
char appEnv[MAXPATHLEN];
diff --git a/xpcom/build/BinaryPath.h b/xpcom/build/BinaryPath.h
--- a/xpcom/build/BinaryPath.h
+++ b/xpcom/build/BinaryPath.h
@@ -126,16 +126,56 @@ class BinaryPath {
} else {
rv = NS_ERROR_FAILURE;
}
CFRelease(executableURL);
return rv;
}
+ static nsresult GetApplicationIni(char aResult[MAXPATHLEN])
+ {
+ // Works even if we're not bundled.
+ CFBundleRef appBundle = CFBundleGetMainBundle();
+ if (!appBundle) {
+ return NS_ERROR_FAILURE;
+ }
+
+ CFURLRef iniURL = CFBundleCopyResourceURL(appBundle, CFSTR("application.ini"),
+ NULL, CFSTR("app"));
+ if (!iniURL) {
+ return NS_ERROR_FAILURE;
+ }
+
+ nsresult rv;
+ if (CFURLGetFileSystemRepresentation(iniURL, false, (UInt8*)aResult,
+ MAXPATHLEN)) {
+ // Sanitize path in case the app was launched from Terminal via
+ // './firefox' for example.
+ size_t readPos = 0;
+ size_t writePos = 0;
+ while (aResult[readPos] != '\0') {
+ if (aResult[readPos] == '.' && aResult[readPos + 1] == '/') {
+ readPos += 2;
+ } else {
+ aResult[writePos] = aResult[readPos];
+ readPos++;
+ writePos++;
+ }
+ }
+ aResult[writePos] = '\0';
+ rv = NS_OK;
+ } else {
+ rv = NS_ERROR_FAILURE;
+ }
+
+ CFRelease(iniURL);
+ return rv;
+ }
+
#elif defined(ANDROID)
static nsresult Get(char aResult[MAXPATHLEN]) {
// On Android, we use the MOZ_ANDROID_LIBDIR variable that is set by the
// Java bootstrap code.
const char* libDir = getenv("MOZ_ANDROID_LIBDIR");
if (!libDir) {
return NS_ERROR_FAILURE;
}
@@ -281,16 +321,29 @@ class BinaryPath {
if (NS_FAILED(Get(path))) {
return nullptr;
}
UniqueFreePtr<char> result;
result.reset(strdup(path));
return result;
}
+#if defined(XP_MACOSX)
+ static UniqueFreePtr<char> GetApplicationIni()
+ {
+ char path[MAXPATHLEN];
+ if (NS_FAILED(GetApplicationIni(path))) {
+ return nullptr;
+ }
+ UniqueFreePtr<char> result;
+ result.reset(strdup(path));
+ return result;
+ }
+#endif
+
#ifdef MOZILLA_INTERNAL_API
static nsresult GetFile(nsIFile** aResult) {
nsCOMPtr<nsIFile> lf;
# ifdef XP_WIN
wchar_t exePath[MAXPATHLEN];
nsresult rv = GetW(exePath);
# else
char exePath[MAXPATHLEN];
diff --git a/mozglue/build/AudioQueueSanitizer.cpp b/mozglue/build/AudioQueueSanitizer.cpp
new file mode 100644
index 000000000000..9efa3255c472
--- /dev/null
+++ b/mozglue/build/AudioQueueSanitizer.cpp
@@ -0,0 +1,91 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+// Work around a use-after-free in the macOS 27 system speech synthesizer.
+//
+// When an utterance finishes, the AudioQueue player in the private
+// TextToSpeech framework (used by both NSSpeechSynthesizer and
+// AVSpeechSynthesizer) enqueues a short de-click ramp that starts from a
+// sample read out of a buffer it has already freed. With the system
+// allocator, which zeroes freed memory, that sample is 0 and the ramp is
+// silent. mozjemalloc poisons freed memory with 0xE5 instead, which reads
+// as -1.36e23 in float32, so every utterance ends with a ~10 ms full-scale
+// burst.
+//
+// We can't fix the framework, so we interpose AudioQueueEnqueueBuffer and
+// zero any float samples that are non-finite or far outside the nominal
+// [-1, 1] range before they reach CoreAudio. Real audio never gets close
+// to kMaxSampleMagnitude, so this only ever affects garbage.
+//
+// dyld only honors __interpose tuples in images loaded at launch, which is
+// why this needs to be in mozglue rather than in XUL (loaded with dlopen)
+// alongside OSXSpeechSynthesizerService.
+
+#include <AudioToolbox/AudioToolbox.h>
+#include <math.h>
+
+namespace {
+
+constexpr float kMaxSampleMagnitude = 16.0f;
+
+void SanitizeBuffer(AudioQueueRef aQueue, AudioQueueBufferRef aBuffer) {
+ AudioStreamBasicDescription format;
+ UInt32 size = sizeof(format);
+ if (AudioQueueGetProperty(aQueue, kAudioQueueProperty_StreamDescription,
+ &format, &size) != noErr) {
+ return;
+ }
+ if (format.mFormatID != kAudioFormatLinearPCM ||
+ !(format.mFormatFlags & kAudioFormatFlagIsFloat) ||
+ format.mBitsPerChannel != 32) {
+ return;
+ }
+
+ float* samples = static_cast<float*>(aBuffer->mAudioData);
+ UInt32 count = aBuffer->mAudioDataByteSize / sizeof(float);
+ for (UInt32 i = 0; i < count; i++) {
+ // Written so that NaN also fails the comparison.
+ if (!(fabsf(samples[i]) <= kMaxSampleMagnitude)) {
+ samples[i] = 0.0f;
+ }
+ }
+}
+
+OSStatus SanitizingEnqueueBuffer(
+ AudioQueueRef aQueue, AudioQueueBufferRef aBuffer, UInt32 aNumPackets,
+ const AudioStreamPacketDescription* aPacketDescs) {
+ SanitizeBuffer(aQueue, aBuffer);
+ return AudioQueueEnqueueBuffer(aQueue, aBuffer, aNumPackets, aPacketDescs);
+}
+
+OSStatus SanitizingEnqueueBufferWithParameters(
+ AudioQueueRef aQueue, AudioQueueBufferRef aBuffer, UInt32 aNumPackets,
+ const AudioStreamPacketDescription* aPacketDescs, UInt32 aTrimFrames,
+ UInt32 aTrimFramesAtEnd, UInt32 aNumParamValues,
+ const AudioQueueParameterEvent* aParamValues,
+ const AudioTimeStamp* aStartTime, AudioTimeStamp* aActualStartTime) {
+ SanitizeBuffer(aQueue, aBuffer);
+ return AudioQueueEnqueueBufferWithParameters(
+ aQueue, aBuffer, aNumPackets, aPacketDescs, aTrimFrames,
+ aTrimFramesAtEnd, aNumParamValues, aParamValues, aStartTime,
+ aActualStartTime);
+}
+
+struct Interpose {
+ const void* mReplacement;
+ const void* mReplacee;
+};
+
+__attribute__((used, section("__DATA,__interpose"))) const Interpose
+ kInterposes[] = {
+ {reinterpret_cast<const void*>(&SanitizingEnqueueBuffer),
+ reinterpret_cast<const void*>(&AudioQueueEnqueueBuffer)},
+ {reinterpret_cast<const void*>(&SanitizingEnqueueBufferWithParameters),
+ reinterpret_cast<const void*>(
+ &AudioQueueEnqueueBufferWithParameters)},
+};
+
+} // namespace
diff --git a/mozglue/build/moz.build b/mozglue/build/moz.build
index f8f01e999e54..111fe5af1b0d 100644
--- a/mozglue/build/moz.build
+++ b/mozglue/build/moz.build
@@ -41,6 +41,14 @@ if CONFIG["OS_TARGET"] == "WINNT":
"winmm.dll",
]
+if CONFIG["OS_TARGET"] == "Darwin" and FORCE_SHARED_LIB:
+ SOURCES += [
+ "AudioQueueSanitizer.cpp",
+ ]
+ OS_LIBS += [
+ "-framework AudioToolbox",
+ ]
+
if CONFIG["MOZ_WIDGET_TOOLKIT"]:
if CONFIG["MOZ_MEMORY"] and FORCE_SHARED_LIB:
pass

File diff suppressed because it is too large Load diff

View file

@ -1,69 +0,0 @@
#!/bin/bash
# Replace channel in ChannelPrefs, with appropriate null-byte padding
#
# ChannelPrefs.framework needs to be signed, which we can't do during normal source builds, so we
# use this to replace 'default' in our custom framework with 'source\0' and store that, and then
# when making real builds we replace 'source\0' with 'release'/'beta'/'dev'/'test' (padded to 7 chars)
set -euo pipefail
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
APP_ROOT_DIR="$(dirname "$SCRIPT_DIR")"
. "$APP_ROOT_DIR/config.sh"
if [ -z "${1:-}" ] || [ -z "${2:-}" ] || [ -z "${3:-}" ]; then
echo "Usage: $0 /path/to/ChannelPrefs.framework/ChannelPrefs from_channel to_channel" >&2
exit 1
fi
binary=$1
from_channel=$2
to_channel=$3
# `strings` has a 4-character minimum by default, but we need 3 for 'dev'
# `-arch all` scans all slices of the universal binary rather than just the host architecture
strings_cmd="strings -n 3 -arch all"
if [ ${#to_channel} -gt 7 ]; then
echo "Channel length cannot exceed 7 characters -- aborting" >&2
exit 1
fi
if [ $($strings_cmd "$binary" | grep -c "$from_channel") -ne 2 ] ; then
echo "$from_channel not found twice in ChannelPrefs" >&2
echo >&2
$strings_cmd "$binary" >&2
exit 1
fi
original_size=$(wc -c "$binary" | awk '{print $1}')
perl -pi -e '
binmode(STDIN);
binmode(STDOUT);
use bytes;
my @channels = qw(release beta dev test source); # List of valid channels
# Channels from Bash
my $from_channel = "'"$from_channel"'";
my $to_channel = "'"$to_channel"'";
if (grep { $_ eq $to_channel } @channels) {
# Pad channels with null bytes
$from_channel .= "\0" x (7 - length($from_channel));
$to_channel .= "\0" x (7 - length($to_channel));
} else {
die "Unknown update channel: $to_channel\n";
}
s/$from_channel/$to_channel/g;
' "$binary"
new_size=$(wc -c "$binary" | awk '{print $1}')
if [ $original_size -ne $new_size ]; then
echo "File size of ChannelPrefs has changed -- aborting" >&2
exit 1
fi
if [ $($strings_cmd "$binary" | grep -c "$to_channel") -ne 2 ] ; then
echo "$to_channel not found twice in ChannelPrefs" >&2
$strings_cmd "$binary" >&2
exit 1
fi
$strings_cmd "$binary"

View file

@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:361730d7cea854b38c6968143555c5f5fe251e1c95f265a6133514ee72ea2c53
size 98904

View file

@ -1,10 +0,0 @@
#!/usr/bin/env python3
# Convert localized app name from "Firefox Software Update" to "Zotero Software Update"
#
# plist is UTF-16
f='updater.app/Contents/Resources/English.lproj/InfoPlist.strings'
with open(f, 'r', encoding='utf-16') as inputfile:
newText = inputfile.read().replace('Firefox', 'Zotero')
with open(f, 'w', encoding='utf-16') as outputfile:
outputfile.write(newText)

Binary file not shown.

@ -1 +0,0 @@
Subproject commit 2e78b1010ad49b4dde70ec9f0094b34a7b6f8965

@ -1 +0,0 @@
Subproject commit 300886d1984de7a0006d7a48310baa0c8c99bea0

@ -1 +0,0 @@
Subproject commit c0aa6e4bef039d94e17e81cb28b1fe9170c45b96

View file

@ -1,64 +0,0 @@
#!/bin/bash
set -euo pipefail
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
APP_ROOT_DIR="$(dirname "$SCRIPT_DIR")"
ROOT_DIR="$(dirname "$(dirname "$SCRIPT_DIR")")"
. "$APP_ROOT_DIR/config.sh"
CHANNEL="release"
BRANCH="10.0"
BUILD_ONLY=0
if [ "`uname`" = "Darwin" ]; then
export SAFARI_APPEX="$ROOT_DIR/../safari-web-extension-builds/ZoteroSafariExtension.appex"
export SAFARI_EXT_RESOURCES="$ROOT_DIR/../safari-web-extension-builds/release/safari"
export SAFARI_APP_EXTENSION="$ROOT_DIR/../safari-app-extension-builds/release/ZoteroSafariExtension.appex"
if [ ! -d "$SAFARI_APPEX" ]; then
echo "Safari extension stub not found at $SAFARI_APPEX -- aborting" >&2
exit 1
fi
if [ ! -f "$SAFARI_EXT_RESOURCES/manifest.json" ]; then
echo "Safari web extension not found in $SAFARI_EXT_RESOURCES -- aborting" >&2
exit 1
fi
if [ ! -d "$SAFARI_APP_EXTENSION" ]; then
echo "Safari App Extension not found at $SAFARI_APP_EXTENSION -- aborting" >&2
exit 1
fi
fi
while getopts "b" opt; do
case $opt in
b)
BUILD_ONLY=1
;;
esac
shift $((OPTIND-1)); OPTIND=1
done
cd "$SCRIPT_DIR"
./check_requirements
hash=`./get_repo_branch_hash $BRANCH`
./check_app_matches_commit $hash
source_dir=`./get_commit_files $hash`
build_dir=`mktemp -d`
function cleanup {
rm -rf "$source_dir"
rm -rf "$build_dir"
}
trap cleanup EXIT
./prepare_build -s "$source_dir" -o "$build_dir" -c $CHANNEL -m $hash
VERSION="`cat \"$build_dir/version\"`"
./build_for_deploy -d "$build_dir" -p $BUILD_PLATFORMS -c $CHANNEL
if [ $BUILD_ONLY -eq 1 ]; then
echo
echo "Build only -- skipping deploy."
echo "To deploy, run on the deploy server:"
echo " $DEPLOY_PATH/deploy $CHANNEL $VERSION $BUILD_PLATFORMS"
else
ssh $DEPLOY_HOST "$DEPLOY_PATH/deploy" $CHANNEL "$VERSION" $BUILD_PLATFORMS
fi

View file

@ -1,55 +0,0 @@
#!/bin/bash
set -euo pipefail
#
# Zip a file directly into app/omni.ja in staging/
#
# Zip paths are relative to the current directory, so this should be run from
# the client build/ directory
#
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
ROOT_DIR="$(dirname "$SCRIPT_DIR")"
. "$ROOT_DIR/config.sh"
function usage {
cat >&2 <<DONE
Usage: $0 path/to/file
DONE
exit 1
}
if [ -z "${1:-}" ]; then
usage
fi
files="$@"
for file in $files; do
if [ ! -f "$file" ]; then
echo "Error: $file not found!"
exit 1
fi
done
mac_path="$STAGE_DIR/Zotero.app/Contents/Resources"
win_path="$STAGE_DIR/Zotero_win-x64"
linux_path="$STAGE_DIR/Zotero_linux-x86_64"
added=0
build_id=$(date +%Y%m%d%H%M%S)
for path in "$mac_path" "$win_path" "$linux_path"; do
if [ -d "$path" ]; then
echo "$path/app/omni.ja"
echo "Updating $(basename $(dirname $(dirname $path)))"
zip "$path/app/omni.ja" $files
# Bump BuildID so that startup caches are invalidated
perl -pi -e "s/^BuildID=.*/BuildID=$build_id/" "$path/app/application.ini"
added=1
fi
done
if [ $added -eq 0 ]; then
echo "No directories found in staging!"
exit 1
fi

View file

@ -1,62 +0,0 @@
#!/usr/bin/env python3
"""
Update a builds manifest with info on a given build
"""
import argparse
import os
import re
import sys
import shutil
import json
import traceback
MAJOR = None
parser = argparse.ArgumentParser(
description='Update a builds manifest with info on a given build',
formatter_class=argparse.ArgumentDefaultsHelpFormatter)
parser.add_argument('-f', '--file', required=True, help="path to updates.json")
parser.add_argument('-v', '--version', required=True, help='version number of build')
parser.add_argument('-b', '--build_id', required=True, help="build ID ('20160801142343')")
args = parser.parse_args()
def main():
try:
file = args.file
version = args.version
short_version = re.match(r'\d+\.\d+', version).group(0)
# Back up JSON file
shutil.copy2(file, file + '.bak')
# Read in existing file
with open(file) as f:
updates = json.loads(f.read())
updates.append({
'version': version,
'buildID': args.build_id,
'detailsURL': f'https://www.zotero.org/support/{short_version}_changelog',
'major': MAJOR
})
# Keep last 5 entries
updates = updates[-5:]
# Write new file
updates = json.dumps(updates, indent=2)
with open(file, 'w') as f:
f.write(updates + "\n")
print(updates)
return 0
except Exception as err:
sys.stderr.write("\n" + traceback.format_exc())
return 1
if __name__ == '__main__':
sys.exit(main())

View file

@ -1,64 +0,0 @@
#!/bin/bash
set -euo pipefail
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
APP_ROOT_DIR="$(dirname "$SCRIPT_DIR")"
ROOT_DIR="$(dirname "$(dirname "$SCRIPT_DIR")")"
. "$APP_ROOT_DIR/config.sh"
CHANNEL="beta"
BRANCH="main"
BUILD_ONLY=0
if [ "`uname`" = "Darwin" ]; then
export SAFARI_APPEX="$ROOT_DIR/../safari-web-extension-builds/ZoteroSafariExtension.appex"
export SAFARI_EXT_RESOURCES="$ROOT_DIR/../safari-web-extension-builds/beta/safari"
export SAFARI_APP_EXTENSION="$ROOT_DIR/../safari-app-extension-builds/beta/ZoteroSafariExtension.appex"
if [ ! -d "$SAFARI_APPEX" ]; then
echo "Safari extension stub not found at $SAFARI_APPEX -- aborting" >&2
exit 1
fi
if [ ! -f "$SAFARI_EXT_RESOURCES/manifest.json" ]; then
echo "Safari web extension not found in $SAFARI_EXT_RESOURCES -- aborting" >&2
exit 1
fi
if [ ! -d "$SAFARI_APP_EXTENSION" ]; then
echo "Safari App Extension not found at $SAFARI_APP_EXTENSION -- aborting" >&2
exit 1
fi
fi
while getopts "b" opt; do
case $opt in
b)
BUILD_ONLY=1
;;
esac
shift $((OPTIND-1)); OPTIND=1
done
cd "$SCRIPT_DIR"
./check_requirements
hash=`./get_repo_branch_hash $BRANCH`
./check_app_matches_commit $hash
source_dir=`./get_commit_files $hash`
build_dir=`mktemp -d`
function cleanup {
rm -rf "$source_dir"
rm -rf "$build_dir"
}
trap cleanup EXIT
./prepare_build -s "$source_dir" -o "$build_dir" -c $CHANNEL -m $hash
VERSION="`cat \"$build_dir/version\"`"
./build_for_deploy -d "$build_dir" -p $BUILD_PLATFORMS -c $CHANNEL
if [ $BUILD_ONLY -eq 1 ]; then
echo
echo "Build only -- skipping deploy."
echo "To deploy, run on the deploy server:"
echo " $DEPLOY_PATH/deploy $CHANNEL $VERSION $BUILD_PLATFORMS"
else
ssh $DEPLOY_HOST "$DEPLOY_PATH/deploy" $CHANNEL "$VERSION" $BUILD_PLATFORMS
fi

View file

@ -1,98 +0,0 @@
#!/bin/bash -e
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
APP_ROOT_DIR="$(dirname "$SCRIPT_DIR")"
ROOT_DIR="$(dirname $APP_ROOT_DIR)"
# Set ZOTERO_PROFILE environment variable to choose profile
profile_args=()
if [ -n "${ZOTERO_PROFILE:-}" ]; then
profile_args=(-p "$ZOTERO_PROFILE")
fi
FORCE_FULL=0
NO_REBUILD=0
SKIP_BUNDLED_FILES=0
DEBUGGER=0
while getopts "rfnbd" opt; do
case $opt in
r)
# Deprecated -- rebuilding is now the default
echo "-r is deprecated -- rebuilding is now the default (use -n to skip)" >&2
;;
f)
FORCE_FULL=1
;;
n)
NO_REBUILD=1
;;
b)
SKIP_BUNDLED_FILES=1
;;
d)
DEBUGGER=1
;;
\?)
exit 1
;;
esac
done
# Remove options from $@
shift $((OPTIND-1))
if [ $NO_REBUILD -eq 0 ]; then
PARAMS=""
if [ $DEBUGGER -eq 1 ]; then
PARAMS="-t"
fi
if [ $FORCE_FULL -eq 1 ]; then
PARAMS="$PARAMS -f"
fi
# Check if build watch is running
# If not, run now
if ! ps u | grep js-build/build.js | grep -v grep > /dev/null; then
echo "Running JS build process"
echo
cd $ROOT_DIR
# TEMP: --openssl-legacy-provider avoids a build error in pdf.js
NODE_OPTIONS=--openssl-legacy-provider node js-build/build.js
echo
fi
"$SCRIPT_DIR/dir_build" $PARAMS
fi
PARAMS=""
if [ $SKIP_BUNDLED_FILES -eq 1 ]; then
PARAMS="$PARAMS -ZoteroSkipBundledFiles"
fi
if [ $DEBUGGER -eq 1 ]; then
PARAMS="$PARAMS -jsdebugger"
else
PARAMS="$PARAMS -jsconsole"
fi
if [ "`uname`" = "Darwin" ]; then
command="Zotero.app/Contents/MacOS/zotero"
elif [ "`uname`" = "Linux" ]; then
if [[ "`uname -m`" = "aarch64" ]]; then
command="Zotero_linux-arm64/zotero"
else
command="Zotero_linux-x86_64/zotero"
fi
elif [ "`uname -o 2> /dev/null`" = "Cygwin" ]; then
command="Zotero_win-x64/zotero.exe"
else
echo "Unknown platform" >&2
exit 1
fi
echo
"$APP_ROOT_DIR/staging/$command" "${profile_args[@]}" -ZoteroDebugText $PARAMS "$@"

View file

@ -1,167 +0,0 @@
#!/bin/bash
#
# Builds Zotero and uploads to S3 and deploy server, but does not make the build live.
# To make the build live, run the deploy script on the deploy server (or via SSH).
#
set -euo pipefail
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
ROOT_DIR="$(dirname "$SCRIPT_DIR")"
. "$ROOT_DIR/config.sh"
function usage {
cat >&2 <<DONE
Usage: $0 -d SOURCE_DIR -c CHANNEL -p PLATFORMS
-d SOURCE_DIR Source directory to build from
-c CHANNEL Release channel ('release', 'beta', 'dev')
-p PLATFORMS Platforms to build (m=Mac, w=Windows, l=Linux)
-i INCREMENTALS Number of incremental builds to create
DONE
exit 1
}
SOURCE_DIR=""
CHANNEL=""
PLATFORMS=""
while getopts "d:c:p:i:" opt; do
case $opt in
d)
SOURCE_DIR="$OPTARG"
if [ ! -d "$SOURCE_DIR" ]; then
echo "$SOURCE_DIR not found"
exit 1
fi
;;
c)
CHANNEL="$OPTARG"
;;
p)
PLATFORMS="$OPTARG"
;;
i)
NUM_INCREMENTALS="$OPTARG"
;;
*)
usage
;;
esac
shift $((OPTIND-1)); OPTIND=1
done
if [[ -z "$SOURCE_DIR" ]] || [[ -z "$CHANNEL" ]] || [[ -z "$PLATFORMS" ]]; then
usage
fi
"$SCRIPT_DIR"/check_requirements
VERSION="`cat \"$SOURCE_DIR\"/version`"
if [ -z "$VERSION" ]; then
echo "Error getting version from $SOURCE_DIR/version"
exit 1
fi
# Enforce signing unless a test build or macOS, which doesn't start otherwise
if [[ "$CHANNEL" != "test" || $PLATFORMS = "m" ]]; then
SIGN="-e"
else
SIGN=""
fi
# Build Zotero
"$ROOT_DIR/build.sh" -d "$SOURCE_DIR" -p $PLATFORMS -c $CHANNEL $SIGN
BUILD_ID=`cat "$DIST_DIR/build_id"`
if [ -z "$BUILD_ID" ]; then
echo "Error getting build id"
exit 1
fi
TEMP_DIR=`mktemp -d`
# Clean up on exit
function cleanup {
rm -rf "$TEMP_DIR"
}
trap cleanup EXIT
# Build full update
"$ROOT_DIR/update-packaging/build_autoupdate.sh" -f -c $CHANNEL -p $PLATFORMS -l $VERSION
# Build incremental updates for each platform
for i in `seq 0 1 $((${#PLATFORMS}-1))`
do
case ${PLATFORMS:i:1} in
m)
platform=mac
platform_name=Mac
;;
w)
platform=win
platform_name=Windows
;;
l)
platform=linux
platform_name=Linux
;;
*)
echo "$0: Invalid platform option ${PLATFORMS:i:1}"
usage
;;
esac
echo
echo "Getting $platform_name incrementals"
INCREMENTALS="`\"$SCRIPT_DIR/manage_incrementals\" -c $CHANNEL -p ${PLATFORMS:i:1} -n $NUM_INCREMENTALS`"
# Fetch pinned incrementals from deploy server and merge
PINNED_FILE="$DEPLOY_PATH/manifests/$CHANNEL/pinned-incrementals-$platform"
PINNED=""
if ssh $DEPLOY_HOST "test -f $PINNED_FILE"; then
PINNED="`ssh $DEPLOY_HOST cat $PINNED_FILE`"
fi
# Combine and deduplicate
INCREMENTALS="`echo -e "$INCREMENTALS\n$PINNED" | sort -u | grep -v '^$' || true`"
echo "$INCREMENTALS"
echo
if [ -n "$INCREMENTALS" ]; then
for from in $INCREMENTALS; do
echo "Building incremental update for $platform_name from $from to $VERSION"
"$ROOT_DIR/update-packaging/build_autoupdate.sh" -i "$from" -c "$CHANNEL" -p ${PLATFORMS:i:1} -l $VERSION
echo
done
fi
done
# Upload builds to S3
"$SCRIPT_DIR/upload_builds" $CHANNEL $VERSION
# Upload file lists and build info for each platform
channel_deploy_path="$DEPLOY_PATH/manifests/$CHANNEL"
mkdir "$TEMP_DIR/version_info"
chmod g+ws "$TEMP_DIR/version_info"
cp "$DIST_DIR"/files-* "$TEMP_DIR/version_info"
chmod g+w "$TEMP_DIR"/version_info/files-*
# Generate build-{os}.json for each platform
SHORT_VERSION=$(echo "$VERSION" | grep -oE '^[0-9]+\.[0-9]+')
DETAILS_URL="https://www.zotero.org/support/${SHORT_VERSION}_changelog"
for i in `seq 0 1 $((${#PLATFORMS}-1))`
do
case ${PLATFORMS:i:1} in
m) os_name="mac" ;;
w) os_name="win" ;;
l) os_name="linux" ;;
esac
printf '{\n "buildID": "%s",\n "detailsURL": "%s"\n}\n' "$BUILD_ID" "$DETAILS_URL" \
> "$TEMP_DIR/version_info/build-${os_name}.json"
chmod g+w "$TEMP_DIR/version_info/build-${os_name}.json"
done
rsync -rv "$TEMP_DIR/version_info/" $DEPLOY_HOST:"$channel_deploy_path/$VERSION/"
rm -rf "$STAGE_DIR"/*
echo
echo "Build $VERSION uploaded successfully."
echo "To deploy, run on the deploy server:"
echo " ./deploy $CHANNEL $VERSION $PLATFORMS"

View file

@ -1,37 +0,0 @@
#!/bin/bash
set -euo pipefail
# Check that app/ in this checkout matches app/ in the commit being built.
#
# The build-and-deploy scripts run the build scripts and config from the local
# checkout but build source files from the tip of the remote branch, so a stale
# checkout can silently build with the wrong Gecko version or omni patches.
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
ROOT_DIR="$(dirname "$(dirname "$SCRIPT_DIR")")"
if [ -z "${1:-}" ]; then
echo "Usage: $0 commit-hash" >&2
exit 1
fi
hash=$1
cd "$ROOT_DIR"
if ! git cat-file -e "$hash^{commit}" 2>/dev/null; then
git fetch -q origin
fi
if ! git cat-file -e "$hash^{commit}" 2>/dev/null; then
echo "Commit $hash not found locally after fetching -- aborting" >&2
exit 1
fi
if ! git diff --quiet HEAD "$hash" -- app/; then
echo >&2
echo "app/ files in this checkout differ from app/ in $hash:" >&2
echo >&2
git --no-pager diff --stat HEAD "$hash" -- app/ >&2
echo >&2
echo "Update this checkout (e.g., 'git pull') and try again" >&2
exit 1
fi

View file

@ -1,158 +0,0 @@
#!/bin/bash
set -uo pipefail
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
APP_ROOT_DIR="$(dirname "$SCRIPT_DIR")"
ROOT_DIR="$(dirname "$APP_ROOT_DIR")"
. "$APP_ROOT_DIR/config.sh"
. "$SCRIPT_DIR/utils.sh"
cd "$ROOT_DIR"
platform=`get_current_platform`
FAIL_CMD='echo -e \033[31;1mFAIL\033[0m'
FAIL_CMD_INLINE='echo -n -e \033[31;1mFAIL\033[0m'
FAILED=0
hdr_start=`tput smul`
hdr_stop=`tput rmul`
echo "${hdr_start}Checking build requirements:${hdr_stop}"
echo
echo -n "Checking for Node.js: "
which node || { $FAIL_CMD_INLINE; FAILED=1; }
node_version=$(node -v | cut -c 2-)
echo -n "Checking Node version: $node_version"
if [ $(echo $node_version | cut -d '.' -f1 ) -ge "18" ]; then
echo
else
echo -n " -- must be 18 or later "
{ $FAIL_CMD; FAILED=1; }
fi
echo -n "Checking for Git LFS: "
which git-lfs || { $FAIL_CMD_INLINE; FAILED=1; }
echo "Checking for Git LFS checkouts: "
lfs_files=$(git lfs ls-files -n 2> /dev/null) || { $FAIL_CMD; FAILED=1; }
for lfs_file in $lfs_files; do
echo -n " - $lfs_file: "
file_type=$(file -b $lfs_file)
echo -n $file_type" "
if [ -z "$(echo -n $file_type | grep XZ)" ]; then
{ $FAIL_CMD_INLINE; FAILED=1; echo " -- run 'git lfs install; git lfs pull'"; }
fi
echo
done
echo -n "Checking for perl: "
which perl || { $FAIL_CMD; FAILED=1; }
echo -n "Checking for python3: "
which python3 || { $FAIL_CMD; FAILED=1; }
echo -n "Checking for curl: "
which curl || { $FAIL_CMD; FAILED=1; }
echo -n "Checking for zip: "
which zip || { $FAIL_CMD; FAILED=1; }
echo -n "Checking for unzip: "
which unzip || { $FAIL_CMD; FAILED=1; }
echo -n "Checking for xz: "
which xz || { $FAIL_CMD; FAILED=1; }
echo -n "Checking for awk: "
which awk || { $FAIL_CMD; FAILED=1; }
echo -n "Checking for rsync: "
which rsync || { $FAIL_CMD; FAILED=1; }
if [ $platform = "w" ]; then
echo -n "Checking for 7z: "
which 7z || { $FAIL_CMD; FAILED=1; }
echo -n "Checking for rcedit: "
which rcedit || { $FAIL_CMD; FAILED=1; echo " -- Install with fetch_rcedit"; }
fi
if [ $platform = "w" ]; then
echo
echo "${hdr_start}Checking Windows packaging requirements:${hdr_stop}"
echo
echo -n "Checking for upx: "
which upx || { $FAIL_CMD; FAILED=1; }
echo -n "Checking for uuidgen: "
which uuidgen || { $FAIL_CMD; FAILED=1; }
echo -n "Checking for code-signing script: "
if [ -x "$APP_ROOT_DIR/win/codesign" ]; then
echo "$APP_ROOT_DIR/win/codesign"
else
$FAIL_CMD
FAILED=1
fi
echo -n "Checking for Unicode NSIS: "
if [ -x "`cygpath -u \"${NSIS_DIR}makensis.exe\"`" ]; then
echo "`cygpath -u \"${NSIS_DIR}makensis.exe\"`"
else
$FAIL_CMD
FAILED=1
fi
plugin_path=$(cd "$NSIS_DIR\\Plugins\\x86-unicode" && pwd)
plugins="AppAssocReg ApplicationID InvokeShellVerb nsProcess ShellLink UAC"
echo "Checking for NSIS plugins in $plugin_path"
for i in $plugins; do
echo -n " $i.dll: "
if [ -f "$plugin_path/$i.dll" ]; then
echo OK
else
$FAIL_CMD
FAILED=1
fi
done
fi
if [ $platform = "m" ]; then
echo
echo "${hdr_start}Checking Mac packaging requirements:${hdr_stop}"
echo
echo -n "Checking for codesign: "
which /usr/bin/codesign || { $FAIL_CMD; FAILED=1; }
fi
echo
echo "${hdr_start}Checking distribution requirements:${hdr_stop}"
echo
echo -n "Checking for Mozilla ARchive (MAR) tool: "
which mar || { $FAIL_CMD; FAILED=1; echo " -- Install with fetch_mar_tools"; }
echo -n "Checking for mbsdiff: "
which mbsdiff || { $FAIL_CMD; FAILED=1; echo " -- Install with fetch_mar_tools"; }
echo -n "Checking for rsync: "
which rsync || { $FAIL_CMD; FAILED=1; }
echo -n "Checking for sha512sum/shasum: "
which sha512sum 2>/dev/null || which shasum 2>/dev/null || { $FAIL_CMD; FAILED=1; }
echo -n "Checking for AWS CLI: "
which aws || { $FAIL_CMD; FAILED=1; }
echo -n "Checking for AWS S3 access: "
aws s3 ls $S3_BUCKET/$S3_DIST_PATH | sed 's/^[[:blank:]]*//' || { $FAIL_CMD; FAILED=1; }
echo -n "Checking for deploy host directory access: "
ssh $DEPLOY_HOST ls -d $DEPLOY_PATH || { $FAIL_CMD; FAILED=1; }
exit $FAILED

View file

@ -1,40 +0,0 @@
#!/bin/bash
set -euo pipefail
# Perform ad-hoc code signing of Zotero.app for local usage
#
# Currently we sign only the Word dylib, since that's necessary for Zotero developers to work on
# Word integration on Apple Silicon. If we discover other problems, we can uncomment some of the
# other lines. If you're making a custom build, you can modify this file to sign the entire build
# instead of just the bare minimum needed for development.
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
ROOT_DIR="$(dirname "$SCRIPT_DIR")"
. "$ROOT_DIR/config.sh"
if [ -z "${1:-}" ]; then
echo "Usage: $0 path/to/staging/Zotero.app"
exit 1
fi
APPDIR=$1
DEVELOPER_ID="-"
entitlements_file="$ROOT_DIR/mac/entitlements.xml"
#/usr/bin/codesign --force --options runtime --entitlements "$entitlements_file" --sign "$DEVELOPER_ID" \
# "$APPDIR/Contents/MacOS/XUL" \
# "$APPDIR/Contents/MacOS/updater.app/Contents/MacOS/org.mozilla.updater"
#find "$APPDIR/Contents" -name '*.dylib' -exec /usr/bin/codesign --force --options runtime --entitlements "$entitlements_file" --sign "$DEVELOPER_ID" {} \;
#find "$APPDIR/Contents" -name '*.app' -exec /usr/bin/codesign --force --options runtime --entitlements "$entitlements_file" --sign "$DEVELOPER_ID" {} \;
#/usr/bin/codesign --force --options runtime --entitlements "$entitlements_file" --sign "$DEVELOPER_ID" "$APPDIR/Contents/MacOS/zotero"
# Skip signing of Safari extension, since it's not present for local builds
# Sign final app package
#echo
#/usr/bin/codesign --force --options runtime --entitlements "$entitlements_file" --sign "$DEVELOPER_ID" "$APPDIR"
# Verify app
#/usr/bin/codesign --verify -vvvv "$APPDIR"
find "$APPDIR/Contents" -name 'libZoteroWordIntegration.dylib' -exec /usr/bin/codesign --force --options runtime --entitlements "$entitlements_file" --sign "$DEVELOPER_ID" {} \;

View file

@ -1,76 +0,0 @@
# Any copyright is dedicated to the Public Domain.
# http://creativecommons.org/publicdomain/zero/1.0/
# Creates the precomplete file containing the remove and rmdir application
# update instructions which is used to remove files and directories that are no
# longer present in a complete update. The current working directory is used for
# the location to enumerate and to create the precomplete file.
import io
import os
def get_build_entries(root_path):
"""Iterates through the root_path, creating a list for each file and
directory. Excludes any file paths ending with channel-prefs.js.
"""
rel_file_path_set = set()
rel_dir_path_set = set()
for root, dirs, files in os.walk(root_path):
for file_name in files:
parent_dir_rel_path = root[len(root_path) + 1 :]
rel_path_file = os.path.join(parent_dir_rel_path, file_name)
rel_path_file = rel_path_file.replace("\\", "/")
if not (
rel_path_file.endswith("channel-prefs.js")
or rel_path_file.endswith("update-settings.ini")
or "/ChannelPrefs.framework/" in rel_path_file
or rel_path_file.startswith("ChannelPrefs.framework/")
or "/UpdateSettings.framework/" in rel_path_file
or rel_path_file.startswith("UpdateSettings.framework/")
or "distribution/" in rel_path_file
):
rel_file_path_set.add(rel_path_file)
for dir_name in dirs:
parent_dir_rel_path = root[len(root_path) + 1 :]
rel_path_dir = os.path.join(parent_dir_rel_path, dir_name)
rel_path_dir = rel_path_dir.replace("\\", "/") + "/"
if rel_path_dir.find("distribution/") == -1:
rel_dir_path_set.add(rel_path_dir)
rel_file_path_list = list(rel_file_path_set)
rel_file_path_list.sort(reverse=True)
rel_dir_path_list = list(rel_dir_path_set)
rel_dir_path_list.sort(reverse=True)
return rel_file_path_list, rel_dir_path_list
def generate_precomplete(root_path):
"""Creates the precomplete file containing the remove and rmdir
application update instructions. The given directory is used
for the location to enumerate and to create the precomplete file.
"""
rel_path_precomplete = "precomplete"
# If inside a Mac bundle use the root of the bundle for the path.
if os.path.basename(root_path) == "Resources":
root_path = os.path.abspath(os.path.join(root_path, "../../"))
rel_path_precomplete = "Contents/Resources/precomplete"
precomplete_file_path = os.path.join(root_path, rel_path_precomplete)
# Open the file so it exists before building the list of files and open it
# in binary mode to prevent OS specific line endings.
precomplete_file = io.open(precomplete_file_path, mode="wt", newline="\n")
rel_file_path_list, rel_dir_path_list = get_build_entries(root_path)
for rel_file_path in rel_file_path_list:
precomplete_file.write('remove "' + rel_file_path + '"\n')
for rel_dir_path in rel_dir_path_list:
precomplete_file.write('rmdir "' + rel_dir_path + '"\n')
precomplete_file.close()
if __name__ == "__main__":
generate_precomplete(os.getcwd())

View file

@ -1,41 +0,0 @@
#!/bin/bash
set -euo pipefail
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
APP_ROOT_DIR="$(dirname "$SCRIPT_DIR")"
ROOT_DIR="$(dirname "$(dirname "$SCRIPT_DIR")")"
. "$APP_ROOT_DIR/config.sh"
CHANNEL="dev"
BRANCH="main"
if [ "`uname`" = "Darwin" ]; then
export SAFARI_APPEX="$ROOT_DIR/../safari-web-extension-builds/ZoteroSafariExtension.appex"
export SAFARI_EXT_RESOURCES="$ROOT_DIR/../safari-web-extension-builds/dev/safari"
if [ ! -d "$SAFARI_APPEX" ]; then
echo "Safari extension stub not found at $SAFARI_APPEX -- aborting" >&2
exit 1
fi
if [ ! -f "$SAFARI_EXT_RESOURCES/manifest.json" ]; then
echo "Safari web extension not found in $SAFARI_EXT_RESOURCES -- aborting" >&2
exit 1
fi
fi
cd "$SCRIPT_DIR"
./check_requirements
hash=`./get_repo_branch_hash $BRANCH`
./check_app_matches_commit $hash
source_dir=`./get_commit_files $hash`
build_dir=`mktemp -d`
function cleanup {
rm -rf "$source_dir"
rm -rf "$build_dir"
}
trap cleanup EXIT
./prepare_build -s "$source_dir" -o "$build_dir" -c $CHANNEL -m $hash
VERSION="`cat \"$build_dir/version\"`"
./build_for_deploy -d "$build_dir" -p $BUILD_PLATFORMS -c $CHANNEL -i 1
ssh $DEPLOY_HOST "$DEPLOY_PATH/deploy" $CHANNEL "$VERSION" $BUILD_PLATFORMS

View file

@ -1,175 +0,0 @@
#!/bin/bash
set -euo pipefail
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
APP_ROOT_DIR="$(dirname "$SCRIPT_DIR")"
ROOT_DIR="$(dirname "$(dirname "$SCRIPT_DIR")")"
. "$APP_ROOT_DIR/config.sh"
. "$SCRIPT_DIR/utils.sh"
function usage {
cat >&2 <<DONE
Usage: $0 [options]
If -p is omitted, platform (and, for Windows/Linux, architecture) default to the host system.
Architecture is ignored for Mac builds, which are always shipped as universal binaries.
Options
-p PLATFORM Platform to build (m=Mac, w=Windows, l=Linux)
-a ARCH Target architecture (arm64, x64, win32) — **Windows/Linux only**
-t add devtools
-f force a full rebuild instead of updating the staged build in place
DONE
exit 1
}
platform=""
arch=""
devtools=0
force_full=0
while getopts "tp:a:f" opt; do
case $opt in
t)
devtools=1
;;
p)
for (( i=0; i<${#OPTARG}; i++ )); do
case ${OPTARG:i:1} in
m) platform="m";;
w) platform="w";;
l) platform="l";;
*)
echo "$0: Invalid platform option ${OPTARG:i:1}" >&2
usage
;;
esac
done
;;
a)
arch="$OPTARG"
;;
f)
force_full=1
;;
\?)
usage
;;
esac
done
# Derive platform from host if not provided
if [[ -z $platform ]]; then
case "$(uname -s)" in
Darwin) platform="m" ;;
Linux) platform="l" ;;
CYGWIN*|MINGW*) platform="w" ;;
esac
fi
# Handle architecture rules
if [[ $platform = "m" ]]; then
# No arch for Mac — ignore anything provided
if [[ -n $arch ]]; then
echo "Ignoring -a $arch for Mac build (universal binary)" >&2
fi
arch=""
else
# Windows / Linux: derive arch if not supplied
if [[ -z $arch ]]; then
# An x64 build of Git for Windows runs emulated on Windows on ARM, where it
# reports x86_64 from `uname -m`, while `uname -s` reports the native
# architecture
if [[ $platform = "w" && "$(uname -s)" == *ARM64* ]]; then
arch="arm64"
else
case "$(uname -m)" in
arm64|aarch64) arch="arm64" ;;
x86_64) arch="x64" ;;
esac
fi
fi
fi
CHANNEL="source"
# Remove stale symlinks left behind in build/ when source files are deleted,
# which would otherwise break the build
if [ -d "$ROOT_DIR/build" ]; then
# With -L, -type l matches only broken symlinks
stale_links=$(find -L "$ROOT_DIR/build" -type l -print)
if [ -n "$stale_links" ]; then
echo "Removing stale symlinks from build/:" >&2
echo "$stale_links" >&2
while IFS= read -r link; do
rm "$link"
done <<< "$stale_links"
fi
fi
# Try to update the staged build in place instead of doing a full rebuild
if [[ $force_full -eq 0 ]]; then
incr_cmd=("$SCRIPT_DIR/incremental_update" -p "$platform")
[[ -n $arch ]] && incr_cmd+=( -a "$arch" )
[[ $devtools -eq 1 ]] && incr_cmd+=( -t )
set +e
"${incr_cmd[@]}"
incr_status=$?
set -e
if [ $incr_status -ne 2 ]; then
exit $incr_status
fi
fi
hash=$(git -C "$ROOT_DIR" rev-parse --short HEAD)
build_dir=$(mktemp -d)
manifest_tmp=""
cleanup() {
rm -rf "$build_dir"
if [ -n "$manifest_tmp" ]; then
rm -f "$manifest_tmp"
fi
}
trap cleanup EXIT
# Snapshot the state of build/ and app/ before the build for later incremental
# updates
app_hash=""
if [ -d "$ROOT_DIR/build" ]; then
manifest_tmp=$(mktemp)
generate_build_manifest "$ROOT_DIR/build" > "$manifest_tmp"
app_hash=$(generate_app_hash "$APP_ROOT_DIR")
fi
"$SCRIPT_DIR/prepare_build" -s "$ROOT_DIR/build" -o "$build_dir" -c "$CHANNEL" -m "$hash"
build_cmd=("$APP_ROOT_DIR/build.sh" -d "$build_dir" -p "$platform" -c "$CHANNEL" -s -q)
[[ -n $arch ]] && build_cmd+=( -a "$arch" )
[[ $devtools -eq 1 ]] && build_cmd+=( -t )
"${build_cmd[@]}"
# Save manifest for future incremental updates
if [ -n "$manifest_tmp" ]; then
if [[ -z "${ZOTERO_TEST:-}" ]] || [[ "${ZOTERO_TEST:-}" == "0" ]]; then
include_tests=0
else
include_tests=1
fi
{
echo "#format=2"
echo "#include_tests=$include_tests"
echo "#devtools=$devtools"
echo "#app_hash=$app_hash"
cat "$manifest_tmp"
} > "$STAGE_DIR/.build-manifest"
fi
# Ad-hoc-sign the Word dylib so it works on Apple Silicon. This only needs to
# happen when the staged build is fully rebuilt -- incremental updates don't
# touch the dylib.
if [[ $platform = "m" ]] && [[ "$(uname -s)" = "Darwin" ]]; then
"$SCRIPT_DIR/codesign_local" "$STAGE_DIR/Zotero.app"
fi
echo Done

View file

@ -1,22 +0,0 @@
#!/bin/bash
set -euo pipefail
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
APP_ROOT_DIR="$(dirname "$SCRIPT_DIR")"
cd "$APP_ROOT_DIR"
mkdir -p "xulrunner/bin"
if [ "`uname`" = "Darwin" ]; then
# Mozilla has Linux executables where the Mac files should be, so supply our own Mac builds
curl -o "xulrunner/bin/mar" https://zotero-download.s3.us-east-1.amazonaws.com/tools/mac/102.11.0esr/mar
curl -o "xulrunner/bin/mbsdiff" https://zotero-download.s3.us-east-1.amazonaws.com/tools/mac/102.11.0esr/mbsdiff
elif [ "`uname -o 2> /dev/null`" = "Cygwin" ]; then
# Mozilla doesn't seem to provide Windows versions via its file server anymore, so supply our own
curl -o "xulrunner/bin/mar.exe" https://zotero-download.s3.us-east-1.amazonaws.com/tools/win/102.11.0esr/mar.exe
curl -o "xulrunner/bin/mbsdiff.exe" https://zotero-download.s3.us-east-1.amazonaws.com/tools/win/102.11.0esr/mbsdiff.exe
else
curl -o "xulrunner/bin/mar" https://ftp.mozilla.org/pub/firefox/nightly/2022/05/2022-05-30-09-39-43-mozilla-central/mar-tools/linux64/mar
curl -o "xulrunner/bin/mbsdiff" https://ftp.mozilla.org/pub/firefox/nightly/2022/05/2022-05-30-09-39-43-mozilla-central/mar-tools/linux64/mbsdiff
fi
chmod 755 xulrunner/bin/mar xulrunner/bin/mbsdiff

View file

@ -1,11 +0,0 @@
#!/bin/bash
set -euo pipefail
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
ROOT_DIR="$(dirname "$SCRIPT_DIR")"
cd "$ROOT_DIR"
mkdir -p "xulrunner/bin"
curl -L -o "xulrunner/bin/rcedit.exe" https://github.com/electron/rcedit/releases/download/v1.1.1/rcedit-x86.exe
chmod 755 xulrunner/bin/rcedit

View file

@ -1,855 +0,0 @@
#!/bin/bash
set -euo pipefail
# Copyright (c) 2011 Zotero
# Center for History and New Media
# George Mason University, Fairfax, Virginia, USA
# http://zotero.org
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
APP_ROOT_DIR="$(dirname "$SCRIPT_DIR")"
. "$APP_ROOT_DIR/config.sh"
. "$SCRIPT_DIR/utils.sh"
cd "$APP_ROOT_DIR"
usage() {
cat >&2 <<'DONE'
Usage: fetch_xulrunner.sh -p <m|w|l> [-a ARCH]
Required
-p PLATFORM m (Mac), w (Windows), l (Linux)
Optional / Conditional
-a ARCH - Mac: disallowed (builds are universal)
- Windows: x64 | arm64 | win32
- Linux: x64 (or x86_64) | arm64
If omitted on Windows/Linux, all standard archs are fetched.
DONE
exit 1
}
BUILD_MAC=0
BUILD_WIN=0
BUILD_LINUX=0
arch=""
while getopts 'p:a:' opt; do
case $opt in
p)
for (( i=0; i<${#OPTARG}; i++ )); do
case ${OPTARG:i:1} in
m) BUILD_MAC=1;;
w) BUILD_WIN=1;;
l) BUILD_LINUX=1;;
*) echo "Invalid platform: ${OPTARG:i:1}"; echo; usage;;
esac
done;;
a) arch="$OPTARG";;
*) usage;;
esac
shift $((OPTIND-1)); OPTIND=1
done
# Require at least one platform
if [[ $BUILD_MAC == 0 ]] && [[ $BUILD_WIN == 0 ]] && [[ $BUILD_LINUX == 0 ]]; then
usage
fi
# Sanity‑check arch flag vs platform selections
if [[ $BUILD_MAC == 1 ]]; then
[[ -n $arch ]] && { echo "-a is not allowed for Mac" >&2; echo; usage; }
fi
if [[ $BUILD_WIN == 1 || $BUILD_LINUX == 1 ]]; then
# arch optional; if provided validate & map aliases now
if [[ -n $arch ]]; then
if [[ $BUILD_WIN == 1 && $BUILD_LINUX == 1 ]]; then
echo "-a cannot be used when building both Windows and Linux simultaneously" >&2; echo; usage
fi
if [[ $BUILD_WIN == 1 ]]; then
case $arch in
x64) arch="win-x64" ;;
arm64) arch="win-arm64" ;;
win32|win-x64|win-arm64) ;;
*) echo "Invalid Windows arch: $arch" >&2; echo; usage;;
esac
fi
if [[ $BUILD_LINUX == 1 ]]; then
[[ $arch == x64 ]] && arch="x86_64"
case $arch in x86_64|arm64) ;; *) echo "Invalid Linux arch: $arch" >&2; echo; usage;; esac
fi
fi
fi
function get_utf16_chars {
str=$(echo -n "$1" | xxd -p | fold -w 2 | sed -r 's/(.+)/\\\\x{\1}\\\\x{00}/')
# Add NUL padding
if [ -n "${2:-}" ]; then
# Multiply characters x 2 for UTF-16
for i in `seq 1 $(($2 * 2))`; do
str+=$(echo '\\x{00}')
done
fi
echo $str | xargs | sed 's/ //g'
}
#
# Make various modifications to the stock Firefox app
#
function modify_omni {
platform=$1
mkdir omni
mv omni.ja omni
cd omni
# omni.ja is an "optimized" ZIP file, so use a script from Mozilla to avoid a warning from unzip
# here and to make it work after rezipping below
python3 "$APP_ROOT_DIR/scripts/optimizejars.py" --deoptimize ./ ./ ./
rm -f omni.ja.log
unzip omni.ja
rm omni.ja
rm -r chrome/pdfjs
rm -r modules/narrate
#rm -r modules/translation
rm actors/AboutTranslations{Parent,Child}.sys.mjs
rm actors/CookieBanner{Parent,Child}.sys.mjs
rm actors/PictureInPictureChild.sys.mjs
rm actors/ThumbnailsChild.sys.mjs
rm actors/Translations{Engine,}{Parent,Child}.sys.mjs
rm actors/AudioPlayback{Parent,Child}.sys.mjs
replace_line 'BROWSER_CHROME_URL:.+' 'BROWSER_CHROME_URL: "chrome:\/\/zotero\/content\/zoteroPane.xhtml",' modules/AppConstants.sys.mjs
# Used by OSKeyStore as the master-key label, visible in macOS Keychain Access.
# Verify that OSKeyStore still derives the label from MOZ_APP_BASENAME, so a
# future Mozilla change to a hardcoded string doesn't silently rebrand the
# keychain entry back to "Firefox Encrypted Storage".
replace_line 'MOZ_APP_BASENAME: "Firefox"' 'MOZ_APP_BASENAME: "Zotero"' modules/AppConstants.sys.mjs
check_line 'STORE_LABEL: AppConstants\.MOZ_APP_BASENAME \+ " Encrypted Storage"' modules/OSKeyStore.sys.mjs
# https://firefox-source-docs.mozilla.org/toolkit/components/telemetry/internals/preferences.html
#
# It's not clear that most of these do anything anymore when not compiled in, but just in case
replace_line 'MOZ_REQUIRE_SIGNING:' 'MOZ_REQUIRE_SIGNING: false \&\&' modules/AppConstants.sys.mjs
replace_line 'MOZ_DATA_REPORTING:' 'MOZ_DATA_REPORTING: false \&\&' modules/AppConstants.sys.mjs
replace_line 'MOZ_TELEMETRY_REPORTING:' 'MOZ_TELEMETRY_REPORTING: false \&\&' modules/AppConstants.sys.mjs
replace_line 'MOZ_CRASHREPORTER:' 'MOZ_CRASHREPORTER: false \&\&' modules/AppConstants.sys.mjs
replace_line 'MOZ_UPDATE_CHANNEL:.+' 'MOZ_UPDATE_CHANNEL: "none",' modules/AppConstants.sys.mjs
replace_line '"https:\/\/[^\/]+mozilla.com.+"' '""' modules/AppConstants.sys.mjs
# Don't use Mozilla Maintenance Service on Windows
replace_line 'MOZ_MAINTENANCE_SERVICE:' 'MOZ_MAINTENANCE_SERVICE: false \&\&' modules/AppConstants.sys.mjs
# Continue using app.update.auto in prefs.js on Windows
replace_line 'PER_INSTALLATION_PREFS_PLATFORMS = \["win"\]' 'PER_INSTALLATION_PREFS_PLATFORMS = []' modules/UpdateUtils.sys.mjs
# Prompt if major update is available instead of installing automatically on restart
replace_line 'if \(!updateAuto\) \{' 'if (update.type == "major") {
LOG("UpdateService:_selectAndInstallUpdate - prompting because it is a major update");
AUSTLMY.pingCheckCode(this._pingSuffix, AUSTLMY.CHK_SHOWPROMPT_PREF);
Services.obs.notifyObservers(update, "update-available", "show-prompt");
return;
}
if (!updateAuto) {' modules/UpdateService.sys.mjs
# Avoid console warning about resource://gre/modules/FxAccountsCommon.js
replace_line 'const logins = this._data.logins;' 'const logins = this._data.logins; if (this._data.logins.length != -1) return;' modules/LoginStore.sys.mjs
# Prevent error during network requests
replace_line 'async lazyInit\(\) \{' 'async lazyInit() { if (this.features) return false;' modules/UrlClassifierExceptionListService.sys.mjs
# Silence CrashManager "Could not get children of [...]/Crash Reports/events" spam
replace_line '\/\/ Missing events folders are allowed' '\/\/ Missing events folders are allowed (silence warning)
if (ex) return entries;' modules/CrashManager.sys.mjs
# Several services pull in services-settings (which we strip) and throw
# at profile-after-change. Remove their #init() methods to prevent errors.
replace_line 'async #init\(\) \{' 'async #init() {} async _unused_init() {' modules/EssentialDomainsRemoteSettings.sys.mjs
replace_line 'async #init\(\) \{' 'async #init() {} async _unused_init() {' modules/SimpleURIUnknownSchemesRemoteObserver.sys.mjs
# RemotePermissionService uses a top-level import, so even loading the
# module throws
replace_line 'import \{ RemoteSettings \} from "resource:\/\/services-settings\/remote-settings.sys.mjs";' \
'const RemoteSettings = () => ({ on() {}, get: async () => [] });' \
modules/RemotePermissionService.sys.mjs
replace_line 'pref\("network.captive-portal-service.enabled".+' 'pref("network.captive-portal-service.enabled", false);' greprefs.js
replace_line 'pref\("network.connectivity-service.enabled".+' 'pref("network.connectivity-service.enabled", false);' greprefs.js
replace_line 'pref\("toolkit.telemetry.server".+' 'pref("toolkit.telemetry.server", "");' greprefs.js
replace_line 'pref\("toolkit.telemetry.unified".+' 'pref("toolkit.telemetry.unified", false);' greprefs.js
replace_line 'pref\("media.gmp-manager.url".+' 'pref("media.gmp-manager.url", "");' greprefs.js
#
# # Disable transaction timeout
# perl -pi -e 's/let timeoutPromise/\/*let timeoutPromise/' modules/Sqlite.jsm
# perl -pi -e 's/return Promise.race\(\[transactionPromise, timeoutPromise\]\);/*\/return transactionPromise;/' modules/Sqlite.jsm
# rm -f jsloader/resource/gre/modules/Sqlite.jsm
#
# Disable unwanted components
remove_line '(RemoteSettings|services-|telemetry|Telemetry|URLDecorationAnnotationsService)' components/components.manifest
file="modules/ActorManagerParent.sys.mjs"
# Remove deleted actors
# Entries in the JSWINDOWACTORS/JSPROCESSACTORS literals:
remove_between '^ AudioPlayback: \{' '^ },' $file
remove_between '^ CookieBanner: \{' '^ },' $file
remove_between '^ Thumbnails: \{' '^ },' $file
remove_between '^ Translations: \{' '^ },' $file
remove_between '^ TranslationsEngine: \{' '^ },' $file
# Entries added conditionally after the literals:
remove_between '^ JSWINDOWACTORS\.AboutTranslations = \{' '^ \};' $file
remove_between '^ JSWINDOWACTORS\.PictureInPictureLauncher = \{' '^ \};' $file
remove_between '^ JSWINDOWACTORS\.PictureInPictureToggle = \{' '^ \};' $file
remove_between '^ JSWINDOWACTORS\.PictureInPicture = \{' '^ \};' $file
# Do not trigger LoginManager event that logs an error on autocomplete submission
remove_line 'DOMInputPasswordAdded: \{\},' $file
# On Mac/Linux, ignore relative paths in PATH in Subprocess.pathSearch(), used when a bare command is passed to Utilities.Internal.subprocess()
if [[ $platform != win* ]]; then
replace_line 'let path = PathUtils.join\(dir, bin\);' 'if (!dir.startsWith("\/")) continue; let path = PathUtils.join(dir, bin);' modules/subprocess/subprocess_unix.sys.mjs
fi
# Remove unwanted files
pushd modules
rm Bookmarks*
rm FxAccounts*
echo '' > FingerprintingWebCompatService.sys.mjs
echo '' > PartitioningExceptionListService.sys.mjs
rm Places*
echo '' > PlacesExpiration.sys.mjs
echo '' > PlacesFrecencyRecalculator.sys.mjs
rm -rf services-settings/*
touch services-settings/remote-settings.sys.mjs
# Causes a startup error -- try an empty file or a shim instead?
#rm Telemetry*
rm URLDecorationAnnotationsService.sys.mjs
popd
pushd chrome/toolkit/content/mozapps/extensions
rm -rf default-theme
popd
# fcntl() is variadic, but js-ctypes declares it with a fixed third argument, which violates
# the ABI on every platform. It's harmless on Linux, where variadic and fixed integer
# arguments are passed in the same registers, but Apple's arm64 ABI passes variadic
# arguments on the stack, so the flag goes into a register the callee never reads and
# fcntl() takes it from an uninitialized stack slot instead. F_SETFD can therefore set
# FD_CLOFORK (bit 1, added in macOS 26) rather than FD_CLOEXEC, closing the pipe in the
# forked child and breaking Subprocess spawns, and F_SETFL can silently fail to set
# O_NONBLOCK. Since the value comes from leftover stack contents, this varies by build and
# call path instead of failing consistently -- don't assume it's fixed just because a given
# build works. This change should stay until this is fixed upstream.
if [[ $platform != win* ]]; then
replace_line 'ctypes\.int \/\* \.\.\. \*\/,' '"...",' modules/subprocess/subprocess_shared_unix.js
replace_line 'libc\.fcntl\(fds\[0\], LIBC\.F_SETFD, LIBC\.FD_CLOEXEC\);' 'libc.fcntl(fds[0], LIBC.F_SETFD, ctypes.int(LIBC.FD_CLOEXEC));' modules/subprocess/subprocess_unix.worker.js
replace_line 'libc\.fcntl\(fds\[1\], LIBC\.F_SETFD, LIBC\.FD_CLOEXEC\);' 'libc.fcntl(fds[1], LIBC.F_SETFD, ctypes.int(LIBC.FD_CLOEXEC));' modules/subprocess/subprocess_unix.worker.js
replace_line 'libc\.fcntl\(fds\[1\], LIBC\.F_SETFL, LIBC\.O_NONBLOCK\);' 'libc.fcntl(fds[1], LIBC.F_SETFL, ctypes.int(LIBC.O_NONBLOCK));' modules/subprocess/subprocess_unix.worker.js
replace_line 'libc\.fcntl\(fds\[0\], LIBC\.F_SETFL, LIBC\.O_NONBLOCK\);' 'libc.fcntl(fds[0], LIBC.F_SETFL, ctypes.int(LIBC.O_NONBLOCK));' modules/subprocess/subprocess_unix.sys.mjs
replace_line 'libc\.fcntl\(fds\[0\], LIBC\.F_SETFD, LIBC\.FD_CLOEXEC\);' 'libc.fcntl(fds[0], LIBC.F_SETFD, ctypes.int(LIBC.FD_CLOEXEC));' modules/subprocess/subprocess_unix.sys.mjs
replace_line 'libc\.fcntl\(fds\[1\], LIBC\.F_SETFD, LIBC\.FD_CLOEXEC\);' 'libc.fcntl(fds[1], LIBC.F_SETFD, ctypes.int(LIBC.FD_CLOEXEC));' modules/subprocess/subprocess_unix.sys.mjs
fi
# This file loads remote-settings.sys.mjs, but if it's empty Zotero crashes
replace_line 'async #init\(\) \{' 'async #init() { if (true) { return; }' modules/URLQueryStrippingListService.sys.mjs
# Clear most WebExtension manifest properties
replace_line 'manifest = normalized.value;' 'manifest = normalized.value;
if (this.type == "extension") {
if (!manifest.applications?.zotero?.id) {
this.manifestError("applications.zotero.id not provided");
}
if (!manifest.applications?.zotero?.update_url) {
this.manifestError("applications.zotero.update_url not provided");
}
if (!manifest.applications?.zotero?.strict_max_version) {
this.manifestError("applications.zotero.strict_max_version not provided");
}
manifest.browser_specific_settings = undefined;
manifest.content_scripts = [];
manifest.permissions = [];
manifest.host_permissions = [];
manifest.web_accessible_resources = undefined;
manifest.experiment_apis = {};
}' modules/Extension.sys.mjs
# Use applications.zotero instead of applications.gecko
replace_line 'let bss = manifest.applications\?.gecko' 'let bss = manifest.applications?.zotero' modules/addons/XPIInstall.sys.mjs
replace_line 'manifest.applications\?.gecko' 'manifest.applications?.zotero' modules/Extension.sys.mjs
# When installing addon, use app version instead of toolkit version for targetApplication
replace_line "id: TOOLKIT_ID," "id: '$APP_ID'," modules/addons/XPIInstall.sys.mjs
# Set strictCompatibility to false in beta/dev/source builds to skip strict_max_version check
replace_line 'addon.strictCompatibility = true;' \
'let version = Services.appinfo.version;
addon.strictCompatibility = !version.includes("-beta") && !version.includes("-dev") && !version.includes("SOURCE");' modules/addons/XPIInstall.sys.mjs
# In beta/dev/source builds, ignore the persisted strictCompatibility flag for already-installed
# plugins, so plugins installed on a stable build (where the flag was set to true) aren't marked
# incompatible after upgrading. The manifest isn't re-parsed on app upgrade, so the flag set at
# install time sticks around.
replace_line '!this\.addon\.strictCompatibility' \
'(!this.addon.strictCompatibility || Services.appinfo.version.includes("-beta") || Services.appinfo.version.includes("-dev") || Services.appinfo.version.includes("SOURCE"))' modules/addons/XPIInstall.sys.mjs
replace_line '!this\.strictCompatibility &&' \
'(!this.strictCompatibility || Services.appinfo.version.includes("-beta") || Services.appinfo.version.includes("-dev") || Services.appinfo.version.includes("SOURCE")) &&' modules/addons/XPIDatabase.sys.mjs
# Accept zotero@chnm.gmu.edu for target application to allow Zotero 6 plugins to remain
# installed in Zotero 7
replace_line "if \(targetApp.id == Services.appinfo.ID\) \{" "if (targetApp.id == 'zotero\@chnm.gmu.edu') targetApp.id = '$APP_ID'; if (targetApp.id == Services.appinfo.ID) {" modules/addons/XPIDatabase.sys.mjs
# TEMP: Skip addons without ids until we figure out what's going on with the default theme.
# This fixes plugin updating and other things.
replace_line 'return addons;' 'return addons.filter(addon => addon.id);' modules/addons/XPIDatabase.sys.mjs
# For updates, look for applications.zotero instead of applications.gecko in manifest.json and
# use the app id and version for strict_min_version/strict_max_version comparisons
replace_line 'gecko: \{\},' 'zotero: {},' modules/addons/AddonUpdateChecker.sys.mjs
replace_line 'if \(!\("gecko" in applications\)\) \{' 'if (!("zotero" in applications)) {' modules/addons/AddonUpdateChecker.sys.mjs
replace_line '"gecko not in application entry' '"zotero not in application entry' modules/addons/AddonUpdateChecker.sys.mjs
replace_line 'let app = getProperty\(applications, "gecko", "object"\);' 'let app = getProperty(applications, "zotero", "object");' modules/addons/AddonUpdateChecker.sys.mjs
replace_line "id: TOOLKIT_ID," "id: '$APP_ID'," modules/addons/AddonUpdateChecker.sys.mjs
replace_line 'lazy.AddonManagerPrivate.webExtensionsMinPlatformVersion' '"7.0"' modules/addons/AddonUpdateChecker.sys.mjs
replace_line 'result.targetApplications.push' 'false && result.targetApplications.push' modules/addons/AddonUpdateChecker.sys.mjs
# In beta/dev/source builds, don't set strictCompatibility on parsed update entries so that
# AddonUpdateChecker doesn't reject an available update whose maxVersion is lower than the
# current (non-stable) app version.
replace_line 'result\.strictCompatibility = appEntry\.maxVersion != "\*";' \
'let appVer = Services.appinfo.version; result.strictCompatibility = appEntry.maxVersion != "*" && !appVer.includes("-beta") && !appVer.includes("-dev") && !appVer.includes("SOURCE");' modules/addons/AddonUpdateChecker.sys.mjs
# Set uninstall flag to true if the update config has it set
replace_line 'targetApplications: \[appEntry\],' \
'targetApplications: \[appEntry\],
uninstall: getProperty(update, "uninstall", "boolean"),' modules/addons/AddonUpdateChecker.sys.mjs
# Prevent automatic installation of default theme
# (chrome/toolkit/content/mozapps/extensions/default-theme, removed above)
replace_line 'this.maybeInstallBuiltinAddon\(' 'if (false) this.maybeInstallBuiltinAddon(' modules/addons/XPIProvider.sys.mjs
# Don't log a warning when checking 'distribution/extensions' for addons
replace_line 'logger.warn\(`Checking' 'logger.debug(`Checking' modules/addons/XPIProvider.sys.mjs
# Allow addon installation by bypassing confirmation dialogs. If we want a confirmation dialog,
# we need to either add gXPInstallObserver from browser-addons.js [1][2] or provide our own with
# Ci.amIWebInstallPrompt [3].
#
# [1] https://searchfox.org/mozilla-esr102/rev/5a6d529652045050c5cdedc0558238949b113741/browser/base/content/browser.js#1902-1923
# [2] https://searchfox.org/mozilla-esr102/rev/5a6d529652045050c5cdedc0558238949b113741/browser/base/content/browser-addons.js#201
# [3] https://searchfox.org/mozilla-esr102/rev/5a6d529652045050c5cdedc0558238949b113741/toolkit/mozapps/extensions/AddonManager.sys.mjs#3114-3124
replace_line 'if \(info.addon.installPermissions\) \{' 'if (false) {' modules/AddonManager.sys.mjs
replace_line '\} else if \(info.addon.sitePermissions\) \{' '} else if (false) {' modules/AddonManager.sys.mjs
replace_line '\} else if \(requireConfirm\) \{' '} else if (false) {' modules/AddonManager.sys.mjs
# Make addon listener methods wait for promises, to allow calling asynchronous plugin `shutdown`
# and `uninstall` methods in our `onInstalling` handler
replace_line 'callAddonListeners\(aMethod' 'async callAddonListeners(aMethod' modules/AddonManager.sys.mjs
# Don't need this one to be async, but we can't easily avoid modifying its `listener[aMethod].apply()` call
replace_line 'callManagerListeners\(aMethod' 'async callManagerListeners(aMethod' modules/AddonManager.sys.mjs
replace_line 'AddonManagerInternal.callAddonListeners.apply\(AddonManagerInternal, aArgs\);' \
'return AddonManagerInternal.callAddonListeners.apply(AddonManagerInternal, aArgs);' modules/AddonManager.sys.mjs
replace_line 'listener\[aMethod\].apply\(listener, aArgs\);' \
'let maybePromise = listener[aMethod].apply(listener, aArgs);
if (maybePromise && maybePromise.then) await maybePromise;' modules/AddonManager.sys.mjs
replace_line 'AddonManagerPrivate.callAddonListeners' 'await AddonManagerPrivate.callAddonListeners' modules/addons/XPIInstall.sys.mjs
replace_line 'let uninstall = \(\) => \{' 'let uninstall = async () => {' modules/addons/XPIInstall.sys.mjs
replace_line 'cancelUninstallAddon\(aAddon\)' 'async cancelUninstallAddon(aAddon)' modules/addons/XPIInstall.sys.mjs
# Check for `uninstall` flag in update config and uninstall the addon if set
replace_line 'if \(update && !this.addon.location.locked\) \{' \
'if (update && !this.addon.location.locked) {
if (update.uninstall) {
let aId = this.addon.id;
logger.debug(`AddonUpdateChecker: uninstall addon \${aId} with uninstall flag`);
let addon = await AddonManager.getAddonByID(aId);
if (addon && (addon.permissions & AddonManager.PERM_CAN_UNINSTALL)) {
try {
addon.uninstall();
} catch (err) {
logger.error(`AddonUpdateChecker: error uninstalling addon \${aId} with uninstall flag`, err);
}
sendUpdateAvailableMessages(this, null);
return;
}
else {
logger.error(`AddonUpdateChecker: addon \${aId} with uninstall flag not found or cannot be uninstalled`);
sendUpdateAvailableMessages(this, null);
return;
}
}
' modules/addons/XPIInstall.sys.mjs
# Prevent login manager from trying to load FxAccountsCommon.sys.mjs
replace_line 'return login.hostname == lazy.FXA_PWDMGR_HOST;' 'return false;' modules/storage-json.sys.mjs
# No idea why this is necessary, but without it initialization fails with "TypeError: "constructor" is read-only"
replace_line 'LoginStore.prototype.constructor = LoginStore;' '\/\/LoginStore.prototype.constructor = LoginStore;' modules/LoginStore.sys.mjs
#
# # Allow proxy password saving
# perl -pi -e 's/get _inPrivateBrowsing\(\) \{/get _inPrivateBrowsing() {if (true) { return false; }/' components/nsLoginManagerPrompter.js
#
# # Change text in update dialog
# perl -pi -e 's/A security and stability update for/A new version of/' chrome/en-US/locale/en-US/mozapps/update/updates.properties
# perl -pi -e 's/updateType_major=New Version/updateType_major=New Major Version/' chrome/en-US/locale/en-US/mozapps/update/updates.properties
# perl -pi -e 's/updateType_minor=Security Update/updateType_minor=New Version/' chrome/en-US/locale/en-US/mozapps/update/updates.properties
# perl -pi -e 's/update for &brandShortName; as soon as possible/update as soon as possible/' chrome/en-US/locale/en-US/mozapps/update/updates.dtd
#
# Set available locales
cp "$APP_ROOT_DIR/assets/multilocale.txt" res/multilocale.txt
# Use Zotero URL opening in Mozilla dialogs (e.g., app update dialog)
replace_line 'function openURL\(aURL\) \{' 'function openURL(aURL) {let {Zotero} = ChromeUtils.importESModule("chrome:\/\/zotero\/content\/zotero.mjs"); Zotero.launchURL(aURL); if (true) { return; }' chrome/toolkit/content/global/contentAreaUtils.js
#
# Modify Add-ons window
#
# Prevent display: block from overriding display: none on <hr>s
replace_line 'display: block !important;' 'display: block;' chrome/toolkit/content/global/elements/panel-list.css
file="chrome/toolkit/content/mozapps/extensions/aboutaddons.css"
echo >> $file
# Hide the search bar and the whole sidebar, since we only ever show plugins and the main pane
# is already headed "Manage Your Plugins"
echo '.main-search, #sidebar { display: none; }' >> $file
# Center the content in the window now that it isn't offset by the sidebar
echo '#full { grid-template-columns: 1fr; }' >> $file
echo '#content { max-width: calc(var(--page-main-content-width) + var(--main-margin-start)); margin-inline: auto; }' >> $file
echo '.main-heading { margin-top: 2em; }' >> $file
# Hide Details/Permissions tabs in addon details so we only show details
echo 'addon-details > button-group { display: none !important; }' >> $file
# Hide "Run on sites with restrictions" row and helper message
echo '.addon-detail-row-quarantined-domains { display: none; }' >> $file
echo '.addon-detail-help-row:has([data-l10n-id="addon-detail-quarantined-domains-help"]) { display: none; }' >> $file
# Hide "Report" button from plugin menu
echo 'addon-card addon-options hr:first-of-type { display: none }' >> $file
echo '[data-l10n-id="report-addon-button"] { display: none }' >> $file
# Hide "Debug Addons" and "Manage Extension Shortcuts"
echo 'panel-item[action="debug-addons"], panel-item[action="reset-update-states"] + hr, panel-item[action="manage-shortcuts"] { display: none }' >> $file
# Show cursor feedback on plugin homepage links
echo '.addon-detail-row-homepage .text-link { cursor: pointer; color: LinkText; }' >> $file
echo '.addon-detail-row-homepage .text-link:hover { text-decoration: underline; }' >> $file
file="chrome/toolkit/content/mozapps/extensions/aboutaddons-utils.mjs"
# Hide unsigned-addon warning
replace_line 'export function isUnsignedWarningMessageDisabled\(\) \{' \
'export function isUnsignedWarningMessageDisabled() {if (true) return true;' $file
# Use our own localized string for blocked plugin notification
replace_line 'details-notification-hard-blocked-\$\{typeSuffix\}' 'plugins-blocked-plugin' $file
# Hide Recommendations tab in sidebar and recommendations in main pane
replace_line 'function isDiscoverEnabled\(\) \{' 'function isDiscoverEnabled() {return false;' $file
file="chrome/toolkit/content/mozapps/extensions/components/addon-details.mjs"
# Hide Private Browsing setting in addon details
replace_line 'pbRow\.' '\/\/pbRow.' $file
replace_line 'let isAllowed = await isAllowedInPrivateBrowsing' '\/\/let isAllowed = await isAllowedInPrivateBrowsing' $file
# Open plugin links in external browser
replace_line 'let homepageURL = homepageRow.querySelector\(\"a\"\);' 'let homepageURL = homepageRow.querySelector(\"\.text-link\");' $file
replace_line 'homepageURL.href = addon.homepageURL;' 'homepageURL.setAttribute("href", addon.homepageURL);' $file
replace_line '<a target="_blank" dir="ltr"><\/a>' \
'<label target="_blank" class="text-link" dir="ltr"><\/label>' $file
file="chrome/toolkit/content/mozapps/extensions/components/addon-card.mjs"
# Use our own strings for the removal prompt
replace_line 'let \{ BrowserAddonUI \} = windowRoot.window;' '' $file
replace_line 'await BrowserAddonUI.promptRemoveExtension' 'promptRemoveExtension' $file
# Customize empty-list message
replace_line 'createEmptyListMessage\(\) {' 'createEmptyListMessage() {
var p = document.createElement("p");
p.id = "empty-list-message";
return p;' chrome/toolkit/content/mozapps/extensions/components/addon-list.mjs
# Add zotero.ftl to the addons page for our own localized strings
replace_line 'href="toolkit\/about\/aboutAddons.ftl"' 'href="toolkit\/about\/aboutAddons.ftl" \/>\n <link rel="localization" href="zotero.ftl"' \
chrome/toolkit/content/mozapps/extensions/aboutaddons.html
# TODO: Use our own strings, but for now fix the bundled English ones
replace_line 'Manage Your Extensions' 'Manage Your Plugins' localization/en-US/toolkit/about/aboutAddons.ftl
replace_line 'Add-on' 'Plugin' localization/en-US/toolkit/about/aboutAddons.ftl
replace_line 'add-ons' 'plugins' localization/en-US/toolkit/about/aboutAddons.ftl
replace_line 'Select add-on to install' 'Select plugin to install' localization/en-US/toolkit/about/aboutAddons.ftl
replace_line 'pref\("extensions.htmlaboutaddons.recommendations.enabled".+' 'pref("extensions.htmlaboutaddons.recommendations.enabled", false);' greprefs.js
# Hide Report option
replace_line 'pref\("extensions.abuseReport.enabled".+' 'pref("extensions.abuseReport.enabled", false);' greprefs.js
# The first displayed Services.prompt dialog's size jumps around because sizeToContent() is called twice
# Fix by preventing the first sizeToContent() call if the icon hasn't been loaded yet
replace_line 'window.sizeToContent\(\);' 'if (ui.infoIcon.complete) window.sizeToContent();' chrome/toolkit/content/global/commonDialog.js
replace_line 'ui.infoIcon.addEventListener' 'if (!ui.infoIcon.complete) ui.infoIcon.addEventListener' chrome/toolkit/content/global/commonDialog.js
# Import style into built-in dialogs
replace_line 'id=\"commonDialogWindow\"' \
'id=\"commonDialogWindow\" class=\"zotero-dialog\" drawintitlebar-platforms=\"mac\"' \
chrome/toolkit/content/global/commonDialog.xhtml
# commonDialog.css link is split across multiple lines, so we have to do a weird substitution,
# so check the one-line global.css to make sure the format hasn't changed
check_line '<html:link rel="stylesheet" href="chrome:\/\/global\/skin\/global.css" \/>' chrome/toolkit/content/global/commonDialog.xhtml
replace_line 'chrome:\/\/global\/skin\/commonDialog.css"' \
'chrome:\/\/global\/skin\/commonDialog.css"\/>
<html:link rel="stylesheet" href="chrome:\/\/zotero-platform\/content\/zotero.css"' \
chrome/toolkit/content/global/commonDialog.xhtml
# commonDialog.xhtml can be opened via Services.prompt in the Profile Manager, so check for a profile first
replace_line 'function commonDialogOnLoad\(\) \{' \
'function commonDialogOnLoad() {
try {
Services.dirsvc.get(\"ProfD\", Ci.nsIFile);
Services.scriptloader.loadSubScript(\"chrome:\/\/zotero\/content\/include.js\", this);
Services.scriptloader.loadSubScript(\"chrome:\/\/zotero\/content\/titlebar.js\", this);
Services.scriptloader.loadSubScript(\"chrome:\/\/zotero\/content\/customElements.js\", this);
} catch (e) {}' \
chrome/toolkit/content/global/commonDialog.js
# Use native checkbox instead of Firefox-themed version in prompt dialogs
replace_line '<xul:checkbox' '<xul:checkbox native=\"true\"' chrome/toolkit/content/global/commonDialog.xhtml
# The <browser> CE appends its autoscroll <popup> to document.documentElement, which doesn't work in zoteroPane.xhtml
# (in Firefox browser.xhtml, document.documentElement is <html>, which can contain <popup>s; in zoteroPane.xhtml, it's
# <window>, which can't)
# Fix by appending it to a <popupset> instead
replace_line 'document.documentElement.appendChild\(this._autoScrollPopup\);' 'let popupset = document.querySelector("popupset");
if (!popupset) {
popupset = document.createXULElement("popupset");
document.documentElement.appendChild(popupset);
}
popupset.appendChild(this._autoScrollPopup);' chrome/toolkit/content/global/elements/browser-custom-element.mjs
# Add the dropmarker for toolbarbuttons with wantdropmarker, which Firefox no longer creates
replace_line 'this.appendChild\(this.constructor.fragment.cloneNode\(true\)\);' \
'this.appendChild(this.constructor.fragment.cloneNode(true));
if (this.hasAttribute("wantdropmarker")) {
let dropmarker = document.createXULElement("dropmarker");
dropmarker.setAttribute("type", "menu");
dropmarker.className = "toolbarbutton-menu-dropmarker";
this.appendChild(dropmarker);
}' chrome/toolkit/content/global/elements/toolbarbutton.js
# Let clicks on the dropmarker pass through to the toolbarbutton, which only opens its menu
# when it's the original event target, as xul.css did when Firefox created the dropmarker
echo '.toolbarbutton-menu-dropmarker { pointer-events: none; }' >> chrome/toolkit/content/global/xul.css
# Remove non-native text input styles
remove_between 'html\|input\:where\(' '^}' chrome/toolkit/skin/classic/global/global-shared.css
# Prevent window dragging on scrollbars
echo 'scrollbar { -moz-window-dragging: no-drag; }' >> chrome/toolkit/res/scrollbars.css
# Provide a mechanism for non-UA stylesheets to override the overflow property
# of a text control's anonymous text node child
echo '::placeholder, ::-moz-text-control-editing-root, ::-moz-text-control-preview {
overflow: var(--moz-text-control-overflow);
}' >> chrome/toolkit/res/forms.css
# Size an autocomplete popup to the input that opened it, or to an ancestor that designates
# itself as the width container. Firefox sizes the popup to its content. (For creator inputs.)
replace_line '\/\/ invalidate\(\) depends on the width attribute' \
'let widthElement = aElement.closest(".autocomplete-popup-width-container") || aElement;
this.style.setProperty("--panel-width", Math.max(widthElement.getBoundingClientRect().width, 100) + "px");
\/\/ invalidate() depends on the width attribute' \
chrome/toolkit/content/global/elements/autocomplete-popup.js
zip -qr9XD omni.ja *
mv omni.ja ..
cd ..
python3 "$APP_ROOT_DIR/scripts/optimizejars.py" --optimize ./ ./ ./
rm -rf omni
# Unzip browser/omni.ja and leave unzipped
cd browser
mkdir omni
mv omni.ja omni
cd omni
ls -la
set +e
unzip omni.ja
set -e
rm omni.ja
# Remove Firefox update URLs
remove_line 'pref\("app.update.url.(manual|details)' defaults/preferences/firefox-branding.js
# Remove Firefox overrides (e.g., to use Firefox-specific strings for connection errors)
remove_line '(override)' chrome/chrome.manifest
# Remove WebExtension APIs
remove_line ext-browser.json components/components.manifest
# Don't open a second window if app is already open when launching .exe (Windows) or running via
# command line (macOS)
replace_line 'function dch_handle\(cmdLine\) \{' 'function dch_handle(cmdLine) {
if (cmdLine.state == Ci.nsICommandLine.STATE_REMOTE_AUTO) { return; }
' modules/BrowserContentHandler.sys.mjs
}
mkdir -p xulrunner
cd xulrunner
if [ $BUILD_MAC == 1 ]; then
GECKO_VERSION="$GECKO_VERSION_MAC"
DOWNLOAD_URL="https://ftp.mozilla.org/pub/firefox/releases/$GECKO_VERSION"
rm -rf Firefox.app
if [ -e "Firefox $GECKO_VERSION.app.zip" ]; then
echo "Using Firefox $GECKO_VERSION.app.zip"
unzip "Firefox $GECKO_VERSION.app.zip"
else
curl -fo Firefox.dmg "$DOWNLOAD_URL/mac/en-US/Firefox%20$GECKO_VERSION.dmg"
set +e
hdiutil detach -quiet /Volumes/Firefox 2>/dev/null
set -e
hdiutil attach -quiet Firefox.dmg
cp -a /Volumes/Firefox/Firefox.app .
# Store local copy of unmodified app
zip -r "Firefox $GECKO_VERSION.app.zip" Firefox.app
hdiutil detach -quiet /Volumes/Firefox
fi
# Download custom components (e.g., XUL), as an xz-compressed tarball of the MacOS folder with
# custom files in it
echo
rm -rf MacOS
if [ -n "$custom_components_hash_mac" ]; then
tarfile="Firefox $GECKO_VERSION MacOS.tar.xz"
if [[ "$(uname)" = "Darwin" ]]; then
shasum="shasum -a 256"
else
shasum=sha256sum
fi
download_components() {
echo "Downloading custom Firefox components"
echo
curl -fo "$tarfile" "${custom_components_url}mac/$custom_components_hash_mac.tar.xz"
}
verify_components_hash() {
echo "$custom_components_hash_mac $tarfile" | $shasum -c -
}
if [ ! -e "$tarfile" ]; then
download_components
fi
# Verify hash
echo
if ! verify_components_hash; then
echo "SHA hash mismatch. Redownloading custom Firefox components…"
rm -f "$tarfile"
download_components
echo
if ! verify_components_hash; then
echo "Hash still doesn't match. Aborting."
exit 1
fi
fi
echo
tar xvf "$tarfile"
echo
fi
pushd Firefox.app/Contents/Resources
modify_omni mac
popd
# Replace "FirefoxCP" with "ZoteroCP" for subprocesses ("Isolated Web Content", "Socket Process", "Web Content", etc.)
info_plist=Firefox.app/Contents/MacOS/plugin-container.app/Contents/Resources/English.lproj/InfoPlist.strings
from=$(get_utf16_chars "FirefoxCP")
to=$(get_utf16_chars "ZoteroCP")
perl -pi -e "s/$from/$to/" $info_plist
# Check for UTF-16 "ZoteroCP"
if ! grep -a -q "Z.o.t.e.r.o.C.P." $info_plist; then
echo '"ZoteroCP" not found in InfoPlist.strings after replacement'
exit 1
fi
rm -f Firefox.dmg
echo $("$SCRIPT_DIR/xulrunner_hash" -p m) > hash-mac
fi
if [ $BUILD_WIN == 1 ]; then
GECKO_VERSION="$GECKO_VERSION_WIN"
DOWNLOAD_URL="https://ftp.mozilla.org/pub/firefox/releases/$GECKO_VERSION"
if [[ -n $arch ]]; then
arch_list=("$(get_canonical_arch w $arch)")
else
arch_list=(win-x64 win-arm64 win32)
fi
for arch in "${arch_list[@]}"; do
xdir=firefox-$arch
rm -rf $xdir
mkdir $xdir
archived_file="Firefox Setup $GECKO_VERSION-$arch.exe"
if [ -e "$archived_file" ]; then
echo "Using $archived_file"
cp "$archived_file" "Firefox%20Setup%20$GECKO_VERSION.exe"
else
if [ $arch = "win-x64" ]; then
moz_arch=win64
elif [ $arch = "win-arm64" ]; then
moz_arch=win64-aarch64
else
moz_arch=$arch
fi
curl -fO "$DOWNLOAD_URL/$moz_arch/en-US/Firefox%20Setup%20$GECKO_VERSION.exe"
# Store local copy of unmodified app
cp "Firefox%20Setup%20$GECKO_VERSION.exe" "$archived_file"
fi
7z x Firefox%20Setup%20$GECKO_VERSION.exe -o$xdir 'core/*'
mv $xdir/core $xdir-core
rm -rf $xdir
mv $xdir-core $xdir
# Download custom components, as an architecture-specific ZIP containing xul.dll, etc.
echo
hash_arch_name="${arch/-/_}"
arch_var_name="custom_components_hash_${hash_arch_name}"
hash=${!arch_var_name:-}
if [ -n "$hash" ]; then
zipfile="Firefox $GECKO_VERSION-$arch Components.zip"
# ZIP filename doesn't include "esr" or "win-"
url="${custom_components_url}win/${GECKO_VERSION//esr}-${arch#win-}-$hash.zip"
if [[ "$(uname)" = "Darwin" ]]; then
shasum="shasum -a 256"
else
shasum=sha256sum
fi
download_zip() {
echo "Downloading custom Firefox components"
echo
echo $url
curl -fo "$zipfile" "$url"
}
verify_hash() {
echo "$hash $zipfile" | $shasum -c -
}
# Download if file doesn't exist
if [ ! -e "$zipfile" ]; then
download_zip
fi
echo
if ! verify_hash; then
echo "SHA hash mismatch. Redownloading ZIP…"
rm -f "$zipfile"
download_zip
echo
if ! verify_hash; then
echo "Hash still doesn't match. Aborting."
exit 1
fi
fi
echo
unzip -o "$zipfile" -d "$xdir"
echo
fi
pushd $xdir
#
# NOTE: Below is disabled, since the full UTF-16 string no longer appears directly in the DLL
# -- it's now truncated after "e594e8d1" for x64/win32 and doesn't appear at all for ARM64
#
# Replace "Mozilla-1de4eec8-1241-4177-a864-e594e8d1fb38" with "Zotero" for C:\ProgramData directory
#
# Mozilla uses a UUID in the path because they previously used just "Mozilla" and needed to
# recreate the folder with correct permissions for security reasons, but we never had a folder in
# ProgramData, so we can just create it as "Zotero". Instead of using a custom xul.dll, just
# replace the hard-coded string with "Zotero" and add a bunch of NULs.
#
#from=$(get_utf16_chars "Mozilla-1de4eec8-1241-4177-a864-e594e8d1fb38")
#to=$(get_utf16_chars "Zotero" 38)
#perl -pe "s/$from/$to/" < xul.dll > xul.dll.new
#mv xul.dll.new xul.dll
# Check for UTF-16 "Zotero" in DLL
#
# (The macOS strings command doesn't have an encoding option, so skip on macOS. You need to
# build on Windows to make an installer, so a Windows build from macOS likely isn't being
# deployed.)
#
#if [[ "`uname`" != "Darwin" ]] && [[ -z "$(strings -e l xul.dll | grep -m 1 Zotero)" ]]; then
# echo '"Zotero" not found in xul.dll after replacement'
# exit 1
#fi
# We re-sign DLL in build.sh, but presumably this file, which is for the Widevine CDM,
# isn't vaid anymore
rm xul.dll.sig
modify_omni $arch
# Disable skeleton UI window
# https://forums.zotero.org/discussion/comment/437636/#Comment_437636
replace_line 'pref\("browser\.startup\.preXulSkeletonUI", true\);' 'pref("browser.startup.preXulSkeletonUI", false);' defaults/preferences/firefox.js
popd
# Uncomment to create local copies for reuse
#cp "Firefox%20Setup%20$GECKO_VERSION.exe" "Firefox Setup $GECKO_VERSION-$arch.exe"
rm "Firefox%20Setup%20$GECKO_VERSION.exe"
echo
echo
echo "$( "$SCRIPT_DIR/xulrunner_hash" -p w -a "$arch" )" > "hash-$arch"
done
fi
if [ $BUILD_LINUX == 1 ]; then
GECKO_VERSION="$GECKO_VERSION_LINUX"
DOWNLOAD_URL="https://ftp.mozilla.org/pub/firefox/releases/$GECKO_VERSION"
if [[ -n $arch ]]; then
arch_list=("$arch")
else
arch_list=(x86_64 arm64)
fi
for arch in "${arch_list[@]}"; do
xdir="firefox-linux-$arch"
rm -rf $xdir
archived_file="firefox-$GECKO_VERSION-$arch.tar.xz"
if [ -e "$archived_file" ]; then
echo "Using $archived_file"
cp "$archived_file" "firefox-$GECKO_VERSION.tar.xz"
else
if [ $arch = "arm64" ]; then
moz_arch=aarch64
else
moz_arch=$arch
fi
curl -fO "$DOWNLOAD_URL/linux-$moz_arch/en-US/firefox-$GECKO_VERSION.tar.xz"
# Store local copy of unmodified app
cp "firefox-$GECKO_VERSION.tar.xz" "$archived_file"
fi
tar xvf firefox-$GECKO_VERSION.tar.xz
mv firefox $xdir
pushd $xdir
modify_omni $arch
popd
rm "firefox-$GECKO_VERSION.tar.xz"
echo "$( $SCRIPT_DIR/xulrunner_hash -p l -a "$arch" )" > "hash-linux-${arch}"
done
fi
echo Done

View file

@ -1,21 +0,0 @@
#!/bin/bash
set -euo pipefail
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
ROOT_DIR="$(dirname "$SCRIPT_DIR")"
. "$ROOT_DIR/config.sh"
if [ -z "${1:-}" ]; then
echo "Commit hash not provided"
exit 1
fi
hash="$1"
tmpdir=`mktemp -d`
cd $tmpdir
curl -sS -f -L -o build.zip "https://$S3_BUCKET.s3.amazonaws.com/$S3_CI_ZIP_PATH/$hash.zip" >&2 \
|| (echo "ZIP file not found for commit '$hash'" && exit 1)
unzip build.zip >&2
rm build.zip
echo $tmpdir

View file

@ -1,14 +0,0 @@
#!/bin/bash
set -euo pipefail
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
ROOT_DIR="$(dirname "$SCRIPT_DIR")"
. "$ROOT_DIR/config.sh"
if [ -z "${1:-}" ]; then
echo "Usage: $0 branch"
exit 1
fi
branch=$1
git ls-remote --exit-code $SOURCE_REPO_URL $branch | cut -f 1

View file

@ -1,322 +0,0 @@
#!/bin/bash
set -euo pipefail
#
# Incrementally update a staged build in staging/ by zipping changed files from
# the client build/ directory directly into app/omni.ja, based on a manifest
# saved by dir_build after the last full build.
#
# Only files that are copied into omni.ja unmodified by build.sh can be updated
# this way. If any other file changed (or a file was removed), a full rebuild
# is required.
#
# Exit codes:
# 0 -- staged build was updated (or nothing changed)
# 2 -- a full rebuild is required
#
# This is normally run automatically by dir_build, not directly.
#
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
APP_ROOT_DIR="$(dirname "$SCRIPT_DIR")"
ROOT_DIR="$(dirname "$APP_ROOT_DIR")"
. "$APP_ROOT_DIR/config.sh"
. "$SCRIPT_DIR/utils.sh"
function usage {
cat >&2 <<DONE
Usage: $0 -p PLATFORM [-a ARCH] [-t]
Options
-p PLATFORM platform of the staged build to update (m=Mac, w=Windows, l=Linux)
-a ARCH target architecture (Windows/Linux only)
-t devtools requested
DONE
exit 1
}
platform=""
arch=""
devtools=0
while getopts "p:a:t" opt; do
case $opt in
p)
platform="$OPTARG"
;;
a)
arch="$OPTARG"
;;
t)
devtools=1
;;
*)
usage
;;
esac
done
if [ -z "$platform" ]; then
usage
fi
BUILD_SRC_DIR="$ROOT_DIR/build"
MANIFEST_FILE="$STAGE_DIR/.build-manifest"
function fall_back {
echo "$1 -- performing full build" >&2
exit 2
}
if [ ! -d "$BUILD_SRC_DIR" ]; then
fall_back "No build/ directory"
fi
if [ ! -f "$MANIFEST_FILE" ]; then
fall_back "No manifest from previous build"
fi
if [[ "$(sed -n 's/^#format=//p' "$MANIFEST_FILE")" != "2" ]]; then
fall_back "Unsupported manifest format"
fi
# Make sure a staged build exists for the requested platform
case $platform in
m)
app_dir="$STAGE_DIR/Zotero.app/Contents/Resources"
;;
w)
app_dir="$STAGE_DIR/Zotero_$(get_canonical_arch w "$arch")"
;;
l)
app_dir="$STAGE_DIR/Zotero_linux-$(get_canonical_arch l "$arch")"
;;
*)
fall_back "Unknown platform '$platform'"
;;
esac
if [ ! -f "$app_dir/app/omni.ja" ]; then
fall_back "No staged build for requested platform"
fi
# If the previous build didn't include tests or devtools and they're requested
# now, files are missing from the staged build
manifest_tests=$(sed -n 's/^#include_tests=//p' "$MANIFEST_FILE")
manifest_tests=${manifest_tests:-0}
manifest_devtools=$(sed -n 's/^#devtools=//p' "$MANIFEST_FILE")
manifest_devtools=${manifest_devtools:-0}
if [[ -z "${ZOTERO_TEST:-}" ]] || [[ "${ZOTERO_TEST:-}" == "0" ]]; then
want_tests=0
else
want_tests=1
fi
if [[ $want_tests -eq 1 ]] && [[ $manifest_tests != "1" ]]; then
fall_back "Tests requested but not included in staged build"
fi
if [[ $devtools -eq 1 ]] && [[ $manifest_devtools != "1" ]]; then
fall_back "Devtools requested but not included in staged build"
fi
# If anything changed in app/ (build scripts, assets, bundled modules, Firefox
# runtime), a full rebuild is required
manifest_app_hash=$(sed -n 's/^#app_hash=//p' "$MANIFEST_FILE")
app_hash=$(generate_app_hash "$APP_ROOT_DIR")
if [[ -z "$manifest_app_hash" ]] || [[ "$app_hash" != "$manifest_app_hash" ]]; then
fall_back "Files in app/ changed"
fi
file_list=$(mktemp)
new_stats=$(mktemp)
carried=$(mktemp)
candidates=$(mktemp)
removed=$(mktemp)
cand_entries=$(mktemp)
trap 'rm -f "$file_list" "$new_stats" "$carried" "$candidates" "$removed" "$cand_entries"' EXIT
cd "$BUILD_SRC_DIR"
# Quickly find files that may have changed based on size/mtime, so that only
# those have to be hashed. Unmodified manifest entries are carried over,
# new/modified files become candidates, and files no longer present are
# considered removed.
build_manifest_file_list > "$file_list"
stat_file_list < "$file_list" > "$new_stats"
awk -F'\t' -v carried="$carried" -v candidates="$candidates" -v removed="$removed" '
NR==FNR {
if (/^#/) next
hash[$3] = $1
stat[$3] = $2
next
}
{
if (!($2 in stat)) {
print > candidates
}
else {
if ($1 == stat[$2]) {
print hash[$2] "\t" $0 > carried
}
else {
print > candidates
}
delete stat[$2]
}
}
END {
for (path in stat) print path > removed
}
' "$MANIFEST_FILE" "$new_stats"
# Hash the candidates and compare to the previous hashes to find real changes
# -- A = added, C = changed, R = removed
if [ -s "$candidates" ]; then
paste \
<(cut -f2 "$candidates" | sed 's,^,./,' | tr '\n' '\0' | hash_file_list | cut -f1) \
"$candidates" \
> "$cand_entries"
fi
changes=$(
if [ -s "$cand_entries" ]; then
awk -F'\t' '
NR==FNR {
if (/^#/) next
old[$3] = $1
next
}
{
if (!($3 in old)) print "A\t" $3
else if (old[$3] != $1) print "C\t" $3
}
' "$MANIFEST_FILE" "$cand_entries"
fi
if [ -s "$removed" ]; then
awk '{print "R\t" $0}' "$removed"
fi
)
# Make sure all changed files can be zipped directly into omni.ja, and skip
# ones that aren't included in the staged build
zip_files=()
ftl_files=()
test_copy_files=()
while IFS=$'\t' read -r status path; do
if [ -z "$status" ]; then
continue
fi
if [ "$status" == "R" ]; then
case "$path" in
test/*)
# Ignore removed test files if tests weren't included
if [[ $manifest_tests != "1" ]]; then
continue
fi
;;
esac
fall_back "$path was removed"
fi
case "$path" in
# Copied into localization/ subdirectories by build.sh
chrome/locale/*/zotero/mozilla/*)
fall_back "Can't update $path in place"
;;
# Pruned by prepare_build
chrome/content/zotero/locale/csl/*)
fall_back "Can't update $path in place"
;;
# Copied to localization/<locale>/ in addition to the chrome path
chrome/locale/*/zotero/*.ftl)
zip_files+=("$path")
ftl_files+=("$path")
;;
chrome/*|components/*|resource/*)
zip_files+=("$path")
;;
# Appended to the main chrome.manifest by build.sh
test/chrome.manifest)
fall_back "Can't update $path in place"
;;
test/*)
# If tests weren't included in the staged build, ignore changes
# to test files
if [[ $manifest_tests == "1" ]]; then
zip_files+=("$path")
case "$path" in
# Also copied to tests/ at the top level of the app
test/tests/*)
test_copy_files+=("$path")
;;
esac
fi
;;
*)
fall_back "Can't update $path in place"
;;
esac
done <<< "$changes"
# Find all staged omni.ja files to update (multiple can exist -- e.g., all
# Windows architectures)
omni_files=()
while IFS= read -r file; do
omni_files+=("$file")
done < <(find "$STAGE_DIR" -path '*/app/omni.ja')
if [ ${#zip_files[@]} -gt 0 ]; then
echo "Changed files:"
for path in "${zip_files[@]}"; do
echo " $path"
done
cd "$BUILD_SRC_DIR"
for omni_file in "${omni_files[@]}"; do
echo "Updating ${omni_file#"$STAGE_DIR"/}"
zip -qX "$omni_file" "${zip_files[@]}"
done
# Copy .ftl files to their localization/ paths
if [ ${#ftl_files[@]} -gt 0 ]; then
l10n_dir=$(mktemp -d)
for path in "${ftl_files[@]}"; do
locale=${path#chrome/locale/}
locale=${locale%%/*}
mkdir -p "$l10n_dir/localization/$locale"
cp -L "$path" "$l10n_dir/localization/$locale/$(basename "$path")"
done
pushd "$l10n_dir" > /dev/null
for omni_file in "${omni_files[@]}"; do
zip -qrX "$omni_file" localization
done
popd > /dev/null
rm -rf "$l10n_dir"
fi
# Copy test files to tests/ directories
if [ ${#test_copy_files[@]} -gt 0 ]; then
for path in "${test_copy_files[@]}"; do
for omni_file in "${omni_files[@]}"; do
dest="${omni_file%/app/omni.ja}/tests/${path#test/tests/}"
mkdir -p "$(dirname "$dest")"
cp -L "$path" "$dest"
done
done
fi
# Bump BuildID so that startup caches are invalidated even without
# -purgecaches
build_id=$(date +%Y%m%d%H%M%S)
for omni_file in "${omni_files[@]}"; do
perl -pi -e "s/^BuildID=.*/BuildID=$build_id/" "$(dirname "$omni_file")/application.ini"
done
echo "Updated staged build with ${#zip_files[@]} changed file(s)"
elif [ -n "$changes" ]; then
echo "No staged files changed"
else
echo "No changes since last build"
fi
{
echo "#format=2"
echo "#include_tests=$manifest_tests"
echo "#devtools=$manifest_devtools"
echo "#app_hash=$app_hash"
LC_ALL=C sort -t$'\t' -k3 "$carried" "$cand_entries"
} > "$MANIFEST_FILE.tmp"
mv "$MANIFEST_FILE.tmp" "$MANIFEST_FILE"

View file

@ -1,88 +0,0 @@
#!/bin/bash
#
# Manage list of deployed version numbers for a channel in order to generate incremental builds
#
set -euo pipefail
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
ROOT_DIR="$(dirname "$SCRIPT_DIR")"
. "$ROOT_DIR/config.sh"
function usage {
cat >&2 <<DONE
Usage:
-c CHANNEL Release channel (e.g., 'beta'); defaults to 'release'
-p PLATFORM Platform (m=Mac, w=Windows, l=Linux)
-a VERSION Add version to incrementals list; cannot be used with -n
-n NUM_VERSIONS Number of previous versions to return; cannot be used with -a
DONE
exit 1
}
CHANNEL="release"
PLATFORM=""
VERSION=""
NUM_VERSIONS=""
while getopts "c:p:a:n:" opt; do
case $opt in
c)
CHANNEL="$OPTARG"
;;
p)
case "$OPTARG" in
m) PLATFORM=mac;;
w) PLATFORM=win;;
l) PLATFORM=linux;;
*)
echo "$0: Invalid platform option $OPTARG"
usage
;;
esac
;;
a)
VERSION="$OPTARG"
;;
n)
NUM_VERSIONS="$OPTARG"
;;
*)
usage
;;
esac
shift $((OPTIND-1)); OPTIND=1
done
if [[ -z "$PLATFORM" ]]; then
usage
fi
if [[ -z "$VERSION" ]] && [[ -z "$NUM_VERSIONS" ]]; then
usage
fi
if [[ "$VERSION" ]] && [[ "$NUM_VERSIONS" ]]; then
usage
fi
INCR_FILENAME="incrementals-$PLATFORM"
REMOTE_PATH="$DEPLOY_PATH/manifests/$CHANNEL/$INCR_FILENAME"
INCR_PATH="$DIST_DIR/$INCR_FILENAME"
mkdir -p "$DIST_DIR"
scp $DEPLOY_HOST:"$REMOTE_PATH" "$INCR_PATH" >&2
# Add version to file and reupload
if [ "$VERSION" ]; then
echo "Adding $VERSION to incrementals-$PLATFORM"
echo $VERSION >> "$INCR_PATH"
scp "$INCR_PATH" $DEPLOY_HOST:"$REMOTE_PATH"
# Show last n versions
elif [ "$NUM_VERSIONS" -gt 0 ]; then
# TEMP: Don't include 6.0 versions
#tail -n $NUM_VERSIONS "$INCR_PATH"
set +e
tail -n $NUM_VERSIONS "$INCR_PATH" | grep -v '^6\.0'
set -e
fi
rm "$INCR_PATH"

View file

@ -1,22 +0,0 @@
#!/bin/bash
set -euo pipefail
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
ROOT_DIR="$(dirname "$SCRIPT_DIR")"
. "$ROOT_DIR/config.sh"
. "$SCRIPT_DIR/utils.sh"
function usage {
echo "Usage: $0 id"
exit 1
}
id=${1:-}
if [[ -z "$id" ]]; then
usage
fi
prepare_notary_auth
xcrun notarytool log "$id" "${notary_auth[@]}" notary_log.json
cat notary_log.json

View file

@ -1,19 +0,0 @@
#!/bin/bash
set -euo pipefail
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
ROOT_DIR="$(dirname "$SCRIPT_DIR")"
. "$ROOT_DIR/config.sh"
function usage {
echo "Usage: $0 file"
exit 1
}
file=${1:-}
if [[ -z "$file" ]]; then
usage
fi
echo "Stapling $file"
xcrun stapler staple $file

View file

@ -1,22 +0,0 @@
#!/bin/bash
set -euo pipefail
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
ROOT_DIR="$(dirname "$SCRIPT_DIR")"
. "$ROOT_DIR/config.sh"
. "$SCRIPT_DIR/utils.sh"
function usage {
echo "Usage: $0 file"
exit 1
}
file=${1:-}
if [[ -z "$file" ]]; then
usage
fi
prepare_notary_auth
echo "Uploading ${file##*/} to Apple for notarization" >&2
xcrun notarytool submit $file "${notary_auth[@]}" --wait

View file

@ -1,376 +0,0 @@
# ***** BEGIN LICENSE BLOCK *****
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
#
# The contents of this file are subject to the Mozilla Public License Version
# 1.1 (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
# http://www.mozilla.org/MPL/
#
# Software distributed under the License is distributed on an "AS IS" basis,
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
# for the specific language governing rights and limitations under the
# License.
#
# The Original Code is mozilla.org code
#
# The Initial Developer of the Original Code is
# Mozilla Foundation.
# Portions created by the Initial Developer are Copyright (C) 2010
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Taras Glek <tglek@mozilla.com>
#
# Alternatively, the contents of this file may be used under the terms of
# either the GNU General Public License Version 2 or later (the "GPL"), or
# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
# in which case the provisions of the GPL or the LGPL are applicable instead
# of those above. If you wish to allow use of your version of this file only
# under the terms of either the GPL or the LGPL, and not to allow others to
# use your version of this file under the terms of the MPL, indicate your
# decision by deleting the provisions above and replace them with the notice
# and other provisions required by the GPL or the LGPL. If you do not delete
# the provisions above, a recipient may use your version of this file under
# the terms of any one of the MPL, the GPL or the LGPL.
#
# ***** END LICENSE BLOCK *****
import sys, os, subprocess, struct, re
local_file_header = [
("signature", "uint32"),
("min_version", "uint16"),
("general_flag", "uint16"),
("compression", "uint16"),
("lastmod_time", "uint16"),
("lastmod_date", "uint16"),
("crc32", "uint32"),
("compressed_size", "uint32"),
("uncompressed_size", "uint32"),
("filename_size", "uint16"),
("extra_field_size", "uint16"),
("filename", "filename_size"),
("extra_field", "extra_field_size"),
("data", "compressed_size")
]
cdir_entry = [
("signature", "uint32"),
("creator_version", "uint16"),
("min_version", "uint16"),
("general_flag", "uint16"),
("compression", "uint16"),
("lastmod_time", "uint16"),
("lastmod_date", "uint16"),
("crc32", "uint32"),
("compressed_size", "uint32"),
("uncompressed_size", "uint32"),
("filename_size", "uint16"),
("extrafield_size", "uint16"),
("filecomment_size", "uint16"),
("disknum", "uint16"),
("internal_attr", "uint16"),
("external_attr", "uint32"),
("offset", "uint32"),
("filename", "filename_size"),
("extrafield", "extrafield_size"),
("filecomment", "filecomment_size"),
]
cdir_end = [
("signature", "uint32"),
("disk_num", "uint16"),
("cdir_disk", "uint16"),
("disk_entries", "uint16"),
("cdir_entries", "uint16"),
("cdir_size", "uint32"),
("cdir_offset", "uint32"),
("comment_size", "uint16"),
]
type_mapping = { "uint32":"I", "uint16":"H"}
def format_struct (format):
string_fields = {}
fmt = "<"
for (name,value) in iter(format):
try:
fmt += type_mapping[value][0]
except KeyError:
string_fields[name] = value
return (fmt, string_fields)
def size_of(format):
return struct.calcsize(format_struct(format)[0])
class MyStruct:
def __init__(self, format, string_fields):
self.__dict__["struct_members"] = {}
self.__dict__["format"] = format
self.__dict__["string_fields"] = string_fields
def addMember(self, name, value):
self.__dict__["struct_members"][name] = value
def __getattr__(self, item):
try:
return self.__dict__["struct_members"][item]
except:
pass
print("no %s" %item)
print(self.__dict__["struct_members"])
raise AttributeError
def __setattr__(self, item, value):
if item in self.__dict__["struct_members"]:
self.__dict__["struct_members"][item] = value
else:
raise AttributeError
def pack(self):
extra_data = b""
values = []
string_fields = self.__dict__["string_fields"]
struct_members = self.__dict__["struct_members"]
format = self.__dict__["format"]
for (name,_) in format:
if name in string_fields:
if not isinstance(struct_members[name], bytes):
struct_members[name] = struct_members[name].encode('utf-8')
extra_data = extra_data + struct_members[name]
else:
values.append(struct_members[name]);
return struct.pack(format_struct(format)[0], *values) + extra_data
ENDSIG = 0x06054b50
def assert_true(cond, msg):
if not cond:
raise Exception(msg)
exit(1)
class BinaryBlob:
def __init__(self, f):
self.data = open(f, "rb").read()
self.offset = 0
self.length = len(self.data)
def readAt(self, pos, length):
self.offset = pos + length
return self.data[pos:self.offset]
def read_struct (self, format, offset = None):
if offset == None:
offset = self.offset
(fstr, string_fields) = format_struct(format)
size = struct.calcsize(fstr)
data = self.readAt(offset, size)
ret = struct.unpack(fstr, data)
retstruct = MyStruct(format, string_fields)
i = 0
for (name,_) in iter(format):
member_desc = None
if not name in string_fields:
member_data = ret[i]
i = i + 1
else:
# zip has data fields which are described by other struct fields, this does
# additional reads to fill em in
member_desc = string_fields[name]
member_data = self.readAt(self.offset, retstruct.__getattr__(member_desc))
retstruct.addMember(name, member_data)
# sanity check serialization code
data = self.readAt(offset, self.offset - offset)
out_data = retstruct.pack()
assert_true(out_data == data, "Serialization fail %d !=%d"% (len(out_data), len(data)))
return retstruct
def optimizejar(jar, outjar, inlog = None):
if inlog is not None:
inlog = open(inlog).read().rstrip()
# in the case of an empty log still move the index forward
if len(inlog) == 0:
inlog = []
else:
inlog = inlog.split("\n")
outlog = []
jarblob = BinaryBlob(jar)
dirend = jarblob.read_struct(cdir_end, jarblob.length - size_of(cdir_end))
assert_true(dirend.signature == ENDSIG, "no signature in the end");
cdir_offset = dirend.cdir_offset
readahead = 0
if inlog is None and cdir_offset == 4:
readahead = struct.unpack("<I", jarblob.readAt(0, 4))[0]
print("%s: startup data ends at byte %d" % (outjar, readahead));
total_stripped = 0;
jarblob.offset = cdir_offset
central_directory = []
for i in range(0, dirend.cdir_entries):
entry = jarblob.read_struct(cdir_entry)
if entry.filename[-1:] == "/":
total_stripped += len(entry.pack())
else:
total_stripped += entry.extrafield_size
central_directory.append(entry)
reordered_count = 0
if inlog is not None:
dup_guard = set()
for ordered_name in inlog:
if ordered_name in dup_guard:
continue
else:
dup_guard.add(ordered_name)
found = False
for i in range(reordered_count, len(central_directory)):
if central_directory[i].filename == ordered_name:
# swap the cdir entries
tmp = central_directory[i]
central_directory[i] = central_directory[reordered_count]
central_directory[reordered_count] = tmp
reordered_count = reordered_count + 1
found = True
break
if not found:
print( "Can't find '%s' in %s" % (ordered_name, jar))
outfd = open(outjar, "wb")
out_offset = 0
if inlog is not None:
# have to put central directory at offset 4 cos 0 confuses some tools.
# This also lets us specify how many entries should be preread
dirend.cdir_offset = 4
# make room for central dir + end of dir + 4 extra bytes at front
out_offset = dirend.cdir_offset + dirend.cdir_size + size_of(cdir_end) - total_stripped
outfd.seek(out_offset)
cdir_data = b""
written_count = 0
crc_mapping = {}
dups_found = 0
dupe_bytes = 0
# store number of bytes suggested for readahead
for entry in central_directory:
# read in the header twice..first for comparison, second time for convenience when writing out
jarfile = jarblob.read_struct(local_file_header, entry.offset)
assert_true(jarfile.filename == entry.filename, "Directory/Localheader mismatch")
# drop directory entries
if entry.filename[-1:] == "/":
total_stripped += len(jarfile.pack())
dirend.cdir_entries -= 1
continue
# drop extra field data
else:
total_stripped += jarfile.extra_field_size;
entry.extrafield = jarfile.extra_field = ""
entry.extrafield_size = jarfile.extra_field_size = 0
# January 1st, 2010
entry.lastmod_date = jarfile.lastmod_date = ((2010 - 1980) << 9) | (1 << 5) | 1
entry.lastmod_time = jarfile.lastmod_time = 0
data = jarfile.pack()
outfd.write(data)
old_entry_offset = entry.offset
entry.offset = out_offset
out_offset = out_offset + len(data)
entry_data = entry.pack()
cdir_data += entry_data
expected_len = entry.filename_size + entry.extrafield_size + entry.filecomment_size
assert_true(len(entry_data) != expected_len,
"%s entry size - expected:%d got:%d" % (entry.filename, len(entry_data), expected_len))
written_count += 1
if entry.crc32 in crc_mapping:
dups_found += 1
dupe_bytes += entry.compressed_size + len(data) + len(entry_data)
print("%s\n\tis a duplicate of\n%s\n---"%(entry.filename, crc_mapping[entry.crc32]))
else:
crc_mapping[entry.crc32] = entry.filename;
if inlog is not None:
if written_count == reordered_count:
readahead = out_offset
print("%s: startup data ends at byte %d"%( outjar, readahead));
elif written_count < reordered_count:
pass
#print("%s @ %d" % (entry.filename, out_offset))
elif readahead >= old_entry_offset + len(data):
outlog.append(entry.filename)
reordered_count += 1
if inlog is None:
dirend.cdir_offset = out_offset
if dups_found > 0:
print("WARNING: Found %d duplicate files taking %d bytes"%(dups_found, dupe_bytes))
dirend.cdir_size = len(cdir_data)
dirend.disk_entries = dirend.cdir_entries
dirend_data = dirend.pack()
assert_true(size_of(cdir_end) == len(dirend_data), "Failed to serialize directory end correctly. Serialized size;%d, expected:%d"%(len(dirend_data), size_of(cdir_end)));
outfd.seek(dirend.cdir_offset)
outfd.write(cdir_data)
outfd.write(dirend_data)
# for ordered jars the central directory is written in the begining of the file, so a second central-directory
# entry has to be written in the end of the file
if inlog is not None:
outfd.seek(0)
outfd.write(struct.pack("<I", readahead));
outfd.seek(out_offset)
outfd.write(dirend_data)
print("Stripped %d bytes" % total_stripped)
print("%s %d/%d in %s" % (("Ordered" if inlog is not None else "Deoptimized"),
reordered_count, len(central_directory), outjar))
outfd.close()
return outlog
if len(sys.argv) != 5:
print("Usage: --optimize|--deoptimize %s JAR_LOG_DIR IN_JAR_DIR OUT_JAR_DIR" % sys.argv[0])
exit(1)
jar_regex = re.compile("\\.jar?$")
def optimize(JAR_LOG_DIR, IN_JAR_DIR, OUT_JAR_DIR):
ls = os.listdir(IN_JAR_DIR)
for jarfile in ls:
if not re.search(jar_regex, jarfile):
continue
injarfile = os.path.join(IN_JAR_DIR, jarfile)
outjarfile = os.path.join(OUT_JAR_DIR, jarfile)
logfile = os.path.join(JAR_LOG_DIR, jarfile + ".log")
if not os.path.isfile(logfile):
logfile = None
optimizejar(injarfile, outjarfile, logfile)
def deoptimize(JAR_LOG_DIR, IN_JAR_DIR, OUT_JAR_DIR):
if not os.path.exists(JAR_LOG_DIR):
os.makedirs(JAR_LOG_DIR)
ls = os.listdir(IN_JAR_DIR)
for jarfile in ls:
if not re.search(jar_regex, jarfile):
continue
injarfile = os.path.join(IN_JAR_DIR, jarfile)
outjarfile = os.path.join(OUT_JAR_DIR, jarfile)
logfile = os.path.join(JAR_LOG_DIR, jarfile + ".log")
log = str(optimizejar(injarfile, outjarfile, None))
open(logfile, "wb").write("\n".join(log).encode('utf-8'))
def main():
MODE = sys.argv[1]
JAR_LOG_DIR = sys.argv[2]
IN_JAR_DIR = sys.argv[3]
OUT_JAR_DIR = sys.argv[4]
if MODE == "--optimize":
optimize(JAR_LOG_DIR, IN_JAR_DIR, OUT_JAR_DIR)
elif MODE == "--deoptimize":
deoptimize(JAR_LOG_DIR, IN_JAR_DIR, OUT_JAR_DIR)
else:
print("Unknown mode %s" % MODE)
exit(1)
if __name__ == '__main__':
main()

View file

@ -1,218 +0,0 @@
#!/usr/bin/env python3
import sys
import os
import argparse
import tempfile
import shutil
import subprocess
import re
import fileinput
from collections import OrderedDict
import json
import traceback
# Hack to combine two argparse formatters
class CustomFormatter(argparse.ArgumentDefaultsHelpFormatter, argparse.RawDescriptionHelpFormatter):
pass
parser = argparse.ArgumentParser(
description='Prepare build/ files for the app build process',
formatter_class=CustomFormatter)
parser.add_argument('--source-dir', '-s', required=True, metavar='BUILD_DIR', help='Directory to build from')
parser.add_argument('--output-dir', '-o', required=True, metavar='OUTPUT_DIR', help='Directory to write files to')
parser.add_argument('-c', '--channel', default='source', help='channel to add to dev build version number (e.g., "beta" for "5.0-beta.3+a5f28ca8"), or "release" or "source" to skip')
parser.add_argument('--commit-hash', '-m', metavar='HASH', help='Commit hash (required for non-release builds)')
args = parser.parse_args()
def main():
try:
app_root_dir = os.path.dirname(os.path.dirname(os.path.realpath(__file__)))
lastrev_dir = os.path.join(app_root_dir, 'lastrev')
if not os.path.exists(lastrev_dir):
os.mkdir(lastrev_dir)
tmp_dir = os.path.join(app_root_dir, 'tmp')
if args.commit_hash:
commit_hash = args.commit_hash[0:9]
elif args.channel != "release":
raise Exception("--commit-hash must be specified for non-release builds")
src_dir = args.source_dir
if not os.path.isdir(src_dir):
raise Exception(src_dir + " is not a directory")
output_dir = args.output_dir
if not os.path.isdir(output_dir):
raise Exception(output_dir + " is not a directory")
if os.listdir(output_dir):
raise Exception(output_dir + " is not empty")
log("Using source directory of " + src_dir)
os.chdir(src_dir)
if not os.path.exists('version'):
raise FileNotFoundError("version file not found in {0}".format(src_dir))
# Extract version number from version file
with open('version') as f:
rdf = f.read()
m = re.search('([0-9].+)\\.SOURCE', rdf)
if not m:
raise Exception("Version number not found in version file")
version = m.group(1)
# Remove tmp build directory if it already exists
if os.path.exists(tmp_dir):
shutil.rmtree(tmp_dir)
os.mkdir(tmp_dir)
tmp_src_dir = os.path.join(tmp_dir, 'zotero')
# Export a clean copy of the source tree -- with Python on Windows, where rsync,
# if present at all, doesn't handle Windows-style paths
if os.name == 'nt' or not shutil.which('rsync'):
shutil.copytree(
'.',
tmp_src_dir,
ignore=shutil.ignore_patterns('.*', '#*', 'package.json', 'package-lock.json')
)
else:
subprocess.check_call([
'rsync',
'-aL',
# Exclude hidden files
'--exclude', '.*',
'--exclude', '#*',
'--exclude', 'package.json',
'--exclude', 'package-lock.json',
'.' + os.sep,
tmp_src_dir + os.sep
])
# Make sure the copy worked
d = os.path.join(tmp_src_dir, 'chrome')
if not os.path.isdir(d):
raise FileNotFoundError(d + " not found")
# Delete CSL locale support files
csl_dir = os.path.normpath(tmp_src_dir + '/chrome/content/zotero/locale/csl/')
for root, dirs, files in os.walk(csl_dir, topdown=False):
for name in files:
if not name.endswith('.xml') and name != 'locales.json':
os.remove(os.path.join(root, name))
for name in dirs:
d = os.path.join(root, name)
if not os.listdir(d):
os.rmdir(d)
# Delete styles build script
os.remove(os.path.join(tmp_src_dir, 'styles', 'update'))
translators_dir = os.path.join(tmp_src_dir, 'translators')
# Move deleted.txt out of translators directory
f = os.path.join(translators_dir, 'deleted.txt')
if os.path.exists(f):
shutil.move(f, tmp_src_dir)
# Build translator index
index = OrderedDict()
for fn in sorted((fn for fn in os.listdir(translators_dir)), key=str.lower):
if not fn.endswith('.js'):
continue
with open(os.path.join(translators_dir, fn), 'r', encoding='utf-8') as f:
contents = f.read()
# Parse out the JSON metadata block
m = re.match(r'^\s*{[\S\s]*?}\s*?[\r\n]', contents)
if not m:
raise Exception("Metadata block not found in " + f.name)
metadata = json.loads(m.group(0))
index[metadata["translatorID"]] = {
"fileName": fn,
"label": metadata["label"],
"lastUpdated": metadata["lastUpdated"]
}
# Write translator index as JSON file
with open(os.path.join(tmp_src_dir, 'translators.json'), 'w', encoding='utf-8') as f:
json.dump(index, f, indent=True, ensure_ascii=False)
version_file = os.path.join(tmp_src_dir, 'version')
log('')
log_line()
log('Original version:\n')
dump_file(version_file)
# Modify version as necessary
# The dev build revision number is stored in lastrev/{version}-{channel}.
#
# If we're including it, get the current version number and increment it.
if args.channel not in ["release", "source"]:
lastrev_file = os.path.join(
lastrev_dir, '{0}-{1}'.format(version, args.channel)
)
if not os.path.exists(lastrev_file):
with open(lastrev_file, 'w') as f:
f.write("0")
rev = 1
else:
with open(lastrev_file, 'r') as f:
rev = f.read()
rev = int(rev if rev else 0) + 1
if args.channel == "release":
rev_sub_str = ""
elif args.channel == "source":
rev_sub_str = ".SOURCE.{0}".format(commit_hash)
else:
rev_sub_str = "-{0}.{1}+{2}".format(args.channel, str(rev), commit_hash)
# Update version
for line in fileinput.FileInput(version_file, inplace=1):
line = line.replace('.SOURCE', rev_sub_str)
print(line, file=sys.stdout, end='')
log('Modified version:\n')
dump_file(version_file)
log('')
log_line()
# Move source files to output directory
os.rmdir(output_dir)
shutil.move(tmp_src_dir, output_dir)
# Update lastrev file with new revision number
if args.channel not in ["release", "source"]:
with open(lastrev_file, 'w') as f:
f.write(str(rev))
return 0
except Exception as err:
sys.stderr.write("\n" + traceback.format_exc())
return 1
# Clean up
finally:
if 'tmp_src_dir' in locals() and os.path.exists(tmp_src_dir):
shutil.rmtree(tmp_src_dir)
def dump_file(f):
with open(f, 'r') as f:
log(f.read())
def log(msg):
print(msg, file=sys.stdout)
def log_line():
log('======================================================\n\n')
if __name__ == '__main__':
sys.exit(main())

View file

@ -1,46 +0,0 @@
#!/bin/bash
set -euo pipefail
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
APP_ROOT_DIR="$(dirname "$SCRIPT_DIR")"
ROOT_DIR="$(dirname "$(dirname "$SCRIPT_DIR")")"
. "$APP_ROOT_DIR/config.sh"
CHANNEL="test"
BRANCH="main"
if [ "`uname`" = "Darwin" ]; then
export SAFARI_APPEX="$ROOT_DIR/../safari-web-extension-builds/ZoteroSafariExtension.appex"
export SAFARI_EXT_RESOURCES="$ROOT_DIR/../safari-web-extension-builds/test/safari"
export SAFARI_APP_EXTENSION="$ROOT_DIR/../safari-app-extension-builds/test/ZoteroSafariExtension.appex"
if [ ! -d "$SAFARI_APPEX" ]; then
echo "Safari extension stub not found at $SAFARI_APPEX -- aborting" >&2
exit 1
fi
if [ ! -f "$SAFARI_EXT_RESOURCES/manifest.json" ]; then
echo "Safari web extension not found in $SAFARI_EXT_RESOURCES -- aborting" >&2
exit 1
fi
if [ ! -d "$SAFARI_APP_EXTENSION" ]; then
echo "Safari App Extension not found at $SAFARI_APP_EXTENSION -- aborting" >&2
exit 1
fi
fi
cd "$SCRIPT_DIR"
./check_requirements
hash=`./get_repo_branch_hash $BRANCH`
./check_app_matches_commit $hash
source_dir=`./get_commit_files $hash`
build_dir=`mktemp -d`
function cleanup {
rm -rf "$source_dir"
rm -rf "$build_dir"
}
trap cleanup EXIT
./prepare_build -s "$source_dir" -o "$build_dir" -c $CHANNEL -m $hash
VERSION="`cat \"$build_dir/version\"`"
./build_for_deploy -d "$build_dir" -p $BUILD_PLATFORMS -c $CHANNEL -i 1
ssh $DEPLOY_HOST "$DEPLOY_PATH/deploy" $CHANNEL "$VERSION" $BUILD_PLATFORMS

View file

@ -1,28 +0,0 @@
#!/bin/bash
#
# Upload build archives from 'dist' to S3 with the specified channel and version
#
set -euo pipefail
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
ROOT_DIR="$(dirname "$SCRIPT_DIR")"
. "$ROOT_DIR/config.sh"
function usage {
echo Usage: $0 CHANNEL VERSION >&2
exit 1
}
CHANNEL="${1:-}"
VERSION="${2:-}"
if [[ -z "$CHANNEL" ]] || [[ -z "$VERSION" ]]; then
usage
fi
source_dir="$DIST_DIR"
if [ "`uname -o 2> /dev/null`" = "Cygwin" ]; then
source_dir=$(cygpath -w "$source_dir")
fi
url="s3://$S3_BUCKET/$S3_DIST_PATH/$CHANNEL/$VERSION/"
aws s3 sync --exclude "files-*" --exclude build_id "$source_dir" $url

View file

@ -1,187 +0,0 @@
get_current_platform() {
if [[ "$OSTYPE" == "linux-gnu"* ]]; then
echo l
elif [[ "$OSTYPE" == "darwin"* ]]; then
echo m
elif [[ "$OSTYPE" == "cygwin" ]]; then
echo w
elif [[ "$OSTYPE" == "msys" ]]; then
echo w
# Unknown, so probably Unix-y
else
echo l
fi
}
get_canonical_arch() {
local _platform=$1
local _arch=$2
case $_platform in
w)
case $_arch in
x64) _arch="win-x64" ;;
arm64) _arch="win-arm64" ;;
win32|win-x64|win-arm64) ;;
*) echo "Invalid Windows archicture: $_arch" >&2;;
esac
echo $_arch
;;
l)
[[ $_arch == x64 ]] && _arch="x86_64"
echo $_arch
;;
*)
echo "Invalid platform '$platform'" 2>&1
exit 1
esac
}
# Print a sorted NUL-separated list of the files in the current directory to
# include in the build manifest. Follows symlinks, like the rsync calls in
# prepare_build and build.sh.
function build_manifest_file_list {
# Exclusions match the rsync call in prepare_build
find -L . -mindepth 1 \( -name '.*' -o -name '#*' \) -prune \
-o -type f ! -name 'package.json' ! -name 'package-lock.json' -print0 \
| LC_ALL=C sort -z
}
# Read a NUL-separated file list on stdin and print "size|mtime<TAB>path" for
# each file
function stat_file_list {
if [[ "$OSTYPE" == "darwin"* ]]; then
xargs -0 stat -L -f '%z|%Fm|%N'
else
xargs -0 stat -L -c '%s|%y|%n'
fi | sed -E 's,^([0-9]+[|][^|]+)[|](\./)?,\1'$'\t'','
}
# Read a NUL-separated file list on stdin and print "hash<TAB>path" for each
# file
function hash_file_list {
local md5_cmd
if command -v md5sum > /dev/null 2>&1; then
md5_cmd="md5sum"
else
md5_cmd="md5 -r"
fi
xargs -0 $md5_cmd | sed -E 's,^([0-9a-f]{32}) ?(\./)?,\1'$'\t'','
}
# Generate a manifest of a build directory for incremental updates, with one
# "hash<TAB>size|mtime<TAB>path" line per file, sorted by path
function generate_build_manifest {
local dir=$1
(
cd "$dir"
local file_list
file_list=$(mktemp)
build_manifest_file_list > "$file_list"
paste \
<(hash_file_list < "$file_list" | cut -f1) \
<(stat_file_list < "$file_list")
rm -f "$file_list"
)
}
# Generate a hash of the files in app/ that affect build output, for detecting
# when a staged build can't be updated incrementally. Since some of the files
# are large binaries, use file sizes and modification times rather than
# contents. The xulrunner runtimes are covered by the hash-* files written by
# fetch_xulrunner.
function generate_app_hash {
local app_dir=$1
local md5_cmd
if command -v md5sum > /dev/null 2>&1; then
md5_cmd="md5sum"
else
md5_cmd="md5 -r"
fi
(
cd "$app_dir"
local paths=(assets build.sh config.sh scripts mac win linux modules update-packaging)
if [ -f config-custom.sh ]; then
paths+=(config-custom.sh)
fi
{
if [[ "$OSTYPE" == "darwin"* ]]; then
find -L "${paths[@]}" -name '.*' -prune -o -type f -print0 | xargs -0 stat -L -f '%N|%z|%m'
else
find -L "${paths[@]}" -name '.*' -prune -o -type f -print0 | xargs -0 stat -L -c '%n|%s|%Y'
fi
cat xulrunner/hash-* 2> /dev/null || true
} | LC_ALL=C sort | $md5_cmd | awk '{print $1}'
)
}
function check_line {
pattern=$1
file=$2
if ! grep -E -q "$pattern" "$file"; then
echo "$pattern" not found in "$file" -- aborting 2>&1
exit 1
fi
}
function replace_line {
pattern=$1
replacement=$2
file=$3
if grep -E -q "$pattern" "$file"; then
perl -pi -e "s/$pattern/$replacement/" "$file"
else
echo "$pattern" not found in "$file" -- aborting 2>&1
exit 1
fi
}
function remove_line {
pattern=$1
file=$2
if grep -E -q "$pattern" "$file"; then
grep -E -v "$pattern" "$file" > "$file.tmp"
mv "$file.tmp" "$file"
else
echo "$pattern" not found in "$file" -- aborting 2>&1
exit 1
fi
}
function remove_between {
start_pattern=$1
end_pattern=$2
file=$3
if grep -E -q "$start_pattern" "$file" && grep -E -q "$end_pattern" "$file"; then
perl -ni -e '
if (/'"$start_pattern"'/) { $skip = 1; next; }
elsif ($skip && /'"$end_pattern"'/) { $skip = 0; next; }
print unless $skip;' "$file"
else
echo "$start_pattern" and "$end_pattern" not found in "$file" -- aborting 2>&1
exit 1
fi
}
# Set $notary_auth to notarytool authentication arguments: the keychain profile in
# NOTARIZATION_PROFILE if set, or else the Apple ID and app-specific password
function prepare_notary_auth {
if [[ -n "${NOTARIZATION_PROFILE:-}" ]]; then
notary_auth=(--keychain-profile "$NOTARIZATION_PROFILE")
if [[ -n "$KEYCHAIN" ]]; then
keychain_path="$HOME/Library/Keychains/$KEYCHAIN.keychain-db"
# The keychain may have auto-locked since signing
if [[ -n "$KEYCHAIN_PASSWORD" ]]; then
security unlock-keychain -p "$KEYCHAIN_PASSWORD" "$keychain_path"
fi
notary_auth+=(--keychain "$keychain_path")
fi
else
notary_auth=(--apple-id "$NOTARIZATION_USER" --team-id "$NOTARIZATION_TEAM_ID" --password "$NOTARIZATION_PASSWORD")
fi
}

View file

@ -1,95 +0,0 @@
#!/bin/bash
# Calculates a hash for the processed Firefox package for a given platform and architecture
#
# Usage:
# xulrunner_hash.sh -p <m|w|l> [-a ARCH]
#
# * **Mac (m)** ‑a is disallowed (universal build).
# * **Windows (w)** ‑a is **required**. Accepted values:
# win32 | x64 | arm64
# * **Linux (l)** ‑a is **required**. Accepted values:
# x86_64 | arm64 (alias x64 → x86_64)
set -euo pipefail
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
APP_ROOT_DIR="$(dirname "$SCRIPT_DIR")"
. "$APP_ROOT_DIR/config.sh"
cd "$APP_ROOT_DIR"
platform=""; arch=""
usage() {
cat >&2 <<'DONE'
Usage: xulrunner_hash.sh -p <m|w|l> [-a ARCH]
-p PLATFORM m (mac), w (windows), l (linux) [required]
-a ARCH *required* for Windows & Linux builds
Windows: x64 | arm64 | win32
Linux: x64 (or x86_64) | arm64
Mac: disallowed – always universal
DONE
exit 1
}
while getopts ':p:a:' opt; do
case $opt in
p) platform="$OPTARG";;
a) arch="$OPTARG";;
:) echo "Option -$OPTARG requires an argument" >&2; usage;;
? ) echo "Invalid option: -$OPTARG" >&2; echo; usage;;
esac
shift $((OPTIND-1)); OPTIND=1
done
[[ -z $platform ]] && { echo "-p is required" >&2; echo; usage; }
case $platform in
m)
[[ -n $arch ]] && { echo "-a is not allowed for Mac (universal build)" >&2; echo; usage; }
arch="universal"
GECKO_VERSION="$GECKO_VERSION_MAC"
;;
w)
[[ -z $arch ]] && { echo "-a is required for Windows builds" >&2; echo; usage; }
# Map CLI-friendly aliases → canonical form
case $arch in
x64) arch="win-x64" ;;
arm64) arch="win-arm64" ;;
win32|win-x64|win-arm64) ;; # already canonical
*) echo "Invalid Windows arch: $arch" >&2; echo; usage;;
esac
GECKO_VERSION="$GECKO_VERSION_WIN"
;;
l)
[[ -z $arch ]] && { echo "-a is required for Linux builds" >&2; echo; usage; }
[[ $arch == x64 ]] && arch="x86_64"
case $arch in
x86_64|arm64) ;;
*) echo "Invalid Linux arch: $arch" >&2; echo; usage;;
esac
GECKO_VERSION="$GECKO_VERSION_LINUX"
;;
*)
echo "Invalid platform: $platform" >&2; echo; usage;;
esac
# Concatenate scripts that affect the build
xulrunner_content=$(< "$SCRIPT_DIR/fetch_xulrunner")
xulrunner_content+=$(< "$SCRIPT_DIR/utils.sh")
xulrunner_content+=$(< "$APP_ROOT_DIR/assets/multilocale.txt")
# Get custom components hash
if [[ $platform = "m" ]]; then
components_hash="$custom_components_hash_mac"
else
hash_arch_name="${arch/-/_}"
arch_var_name="custom_components_hash_${hash_arch_name}"
components_hash=${!arch_var_name:-}
fi
input_string="${platform}-${arch}-${components_hash}|${GECKO_VERSION}|${xulrunner_content}"
printf "%s" "$input_string" | openssl dgst -sha256 | awk '{print $NF}'

View file

@ -1,411 +0,0 @@
#!/bin/bash
set -euo pipefail
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
ROOT_DIR="$(dirname "$SCRIPT_DIR")"
. "$ROOT_DIR/config.sh"
UPDATE_STAGE_DIR="$SCRIPT_DIR/staging"
function usage {
cat >&2 <<DONE
Usage: $0 -c CHANNEL [-f] [-i FROM_VERSION] [-p PLATFORMS] [-l] VERSION
Options
-c CHANNEL Release channel ('release', 'beta')
-f Perform full build
-i FROM_VERSION Perform incremental build
-p PLATFORMS Platforms to build (m=Mac, w=Windows, l=Linux)
-l Use local TO directory instead of downloading TO files from S3
DONE
exit 1
}
# From https://gist.github.com/cdown/1163649#gistcomment-1639097
urlencode() {
local LANG=C
local length="${#1}"
for (( i = 0; i < length; i++ )); do
local c="${1:i:1}"
case $c in
[a-zA-Z0-9.~_-]) printf "$c" ;;
*) printf '%%%02X' "'$c" ;;
esac
done
}
BUILD_FULL=0
BUILD_INCREMENTAL=0
FROM=""
CHANNEL=""
BUILD_MAC=0
BUILD_WIN=0
BUILD_LINUX=0
USE_LOCAL_TO=0
while getopts "i:c:p:fl" opt; do
case $opt in
i)
FROM="$OPTARG"
BUILD_INCREMENTAL=1
;;
c)
CHANNEL="$OPTARG"
;;
p)
for i in `seq 0 1 $((${#OPTARG}-1))`
do
case ${OPTARG:i:1} in
m) BUILD_MAC=1;;
w) BUILD_WIN=1;;
l) BUILD_LINUX=1;;
*)
echo "$0: Invalid platform option ${OPTARG:i:1}"
usage
;;
esac
done
;;
f)
BUILD_FULL=1
;;
l)
USE_LOCAL_TO=1
;;
*)
usage
;;
esac
shift $((OPTIND-1)); OPTIND=1
done
shift $(($OPTIND - 1))
TO=${1:-}
if [ -z "$TO" ]; then
usage
fi
if [ -z "$FROM" ] && [ $BUILD_FULL -eq 0 ]; then
usage
fi
if [[ -z "$CHANNEL" ]]; then
echo "Channel not provided" >&2
exit 1
fi
# Require at least one platform
if [[ $BUILD_MAC == 0 ]] && [[ $BUILD_WIN == 0 ]] && [[ $BUILD_LINUX == 0 ]]; then
usage
fi
TO_MAJOR_VERSION="${TO%%.*}"
rm -rf "$UPDATE_STAGE_DIR"
mkdir "$UPDATE_STAGE_DIR"
INCREMENTALS_FOUND=0
for version in "$FROM" "$TO"; do
if [[ $version == "$TO" ]] && [[ $INCREMENTALS_FOUND == 0 ]] && [[ $BUILD_FULL == 0 ]]; then
exit
fi
if [ -z "$version" ]; then
continue
fi
echo "Getting Zotero version $version"
versiondir="$UPDATE_STAGE_DIR/$version"
#
# If -l passed, use main build script's staging directory for TO files rather than downloading
# the given version.
#
# The caller must ensure that the files in ../staging match the platforms and version given.
if [[ $version == $TO && $USE_LOCAL_TO == "1" ]]; then
if [ ! -d "$STAGE_DIR" ]; then
echo "Can't find local TO dir $STAGE_DIR"
exit 1
fi
echo "Using files from $STAGE_DIR"
ln -s "$STAGE_DIR" "$versiondir"
continue
fi
#
# Otherwise, download version from S3
#
mkdir -p "$versiondir"
cd "$versiondir"
# Determine Linux archive extension by major Zotero version
MAJOR_VERSION="${version%%.*}"
if [ "$MAJOR_VERSION" -lt 8 ]; then
LINUX_EXT="tar.bz2"
else
LINUX_EXT="tar.xz"
fi
MAC_ARCHIVE="Zotero-${version}.dmg"
WIN32_ARCHIVE="Zotero-${version}_win32.zip"
WIN_X64_ARCHIVE="Zotero-${version}_win-x64.zip"
WIN_ARM64_ARCHIVE="Zotero-${version}_win-arm64.zip"
LINUX_X86_ARCHIVE="Zotero-${version}_linux-i686.${LINUX_EXT}"
LINUX_X86_64_ARCHIVE="Zotero-${version}_linux-x86_64.${LINUX_EXT}"
LINUX_ARM64_ARCHIVE="Zotero-${version}_linux-arm64.${LINUX_EXT}"
CACHE_DIR="$ROOT_DIR/cache"
if [ ! -e "$CACHE_DIR" ]; then
mkdir "$CACHE_DIR"
fi
# Build archive list (no Linux arm64 before Zotero 8, no Linux i686 from Zotero 11)
ARCHIVES=(
"$MAC_ARCHIVE"
"$WIN32_ARCHIVE"
"$WIN_X64_ARCHIVE"
"$WIN_ARM64_ARCHIVE"
"$LINUX_X86_64_ARCHIVE"
)
if [ "$TO_MAJOR_VERSION" -lt 11 ]; then
ARCHIVES+=("$LINUX_X86_ARCHIVE")
fi
if [ "$MAJOR_VERSION" -ge 8 ]; then
ARCHIVES+=("$LINUX_ARM64_ARCHIVE")
fi
for archive in "${ARCHIVES[@]}"; do
if [[ $archive = "$MAC_ARCHIVE" ]] && [[ $BUILD_MAC != 1 ]]; then
continue
fi
if [[ $archive = "$WIN32_ARCHIVE" ]] && [[ $BUILD_WIN != 1 ]]; then
continue
fi
if [[ $archive = "$WIN_X64_ARCHIVE" ]] && [[ $BUILD_WIN != 1 ]]; then
continue
fi
if [[ $archive = "$WIN_ARM64_ARCHIVE" ]] && [[ $BUILD_WIN != 1 ]]; then
continue
fi
if [[ $archive = "$LINUX_X86_ARCHIVE" ]] && [[ $BUILD_LINUX != 1 ]]; then
continue
fi
if [[ $archive = "$LINUX_X86_64_ARCHIVE" ]] && [[ $BUILD_LINUX != 1 ]]; then
continue
fi
if [[ $archive = "$LINUX_ARM64_ARCHIVE" ]] && [[ $BUILD_LINUX != 1 ]]; then
continue
fi
ETAG_FILE="$CACHE_DIR/$archive.etag"
# Check cache for archive
if [[ -f "$CACHE_DIR/$archive" ]] && [[ -f "$CACHE_DIR/$archive.etag" ]]; then
ETAG="`cat $ETAG_FILE | tr '\n' ' '`"
else
ETAG=""
fi
rm -f $archive
# URL-encode '+' in beta version numbers
ENCODED_VERSION=`urlencode $version`
ENCODED_ARCHIVE=`urlencode $archive`
URL="https://$S3_BUCKET.s3.amazonaws.com/$S3_DIST_PATH/$CHANNEL/$ENCODED_VERSION/$ENCODED_ARCHIVE"
echo "Fetching $URL"
set +e
# Cached version is available
if [ -n "$ETAG" ]; then
HTTP_CODE=$(curl -sS -L -D headers.txt -o $archive -w '%{http_code}' -H "If-None-Match: $ETAG" "$URL")
NEW_ETAG=$(awk 'tolower($1) == "etag:" {print $2}' headers.txt | tr -d '\r' | tail -n 1)
rm -f headers.txt
# If ETag didn't match, cache newly downloaded version
if [ "$HTTP_CODE" = 200 ]; then
echo "ETag for $archive didn't match! -- using new version"
rm -f "$CACHE_DIR/$archive.etag"
cp $archive "$CACHE_DIR/"
echo "$NEW_ETAG" > "$CACHE_DIR/$archive.etag"
# If ETag matched (or there was another error), use cached version
else
echo "Using cached $archive"
cp "$CACHE_DIR/$archive" .
fi
else
curl -sS -f -L -D headers.txt -o $archive "$URL"
NEW_ETAG=$(awk 'tolower($1) == "etag:" {print $2}' headers.txt | tr -d '\r' | tail -n 1)
rm -f headers.txt
# Save archive to cache
rm -f "$CACHE_DIR/$archive.etag"
cp $archive "$CACHE_DIR/"
echo "$NEW_ETAG" > "$CACHE_DIR/$archive.etag"
fi
set -e
done
# Delete cached archives older than 14 days
find "$CACHE_DIR" -maxdepth 1 -type f -ctime +14 -delete
# Delete cached diffs and compressed files not created or used in 60 days
# (cache hits touch the entries)
if [ -d "$CACHE_DIR/update-packaging" ]; then
find "$CACHE_DIR/update-packaging" -type f -ctime +60 -delete
fi
# Unpack Zotero.app
if [ $BUILD_MAC == 1 ]; then
if [ -f "$MAC_ARCHIVE" ]; then
set +e
hdiutil detach -quiet /Volumes/Zotero 2>/dev/null
set -e
hdiutil attach -quiet "$MAC_ARCHIVE"
cp -R /Volumes/Zotero/Zotero.app "$versiondir"
rm "$MAC_ARCHIVE"
hdiutil detach -quiet /Volumes/Zotero
INCREMENTALS_FOUND=1
else
echo "$MAC_ARCHIVE not found"
fi
fi
# Unpack Windows zips
if [ $BUILD_WIN == 1 ]; then
if [[ -f "$WIN32_ARCHIVE" ]] && [[ -f "$WIN_X64_ARCHIVE" ]] && [[ -f "$WIN_ARM64_ARCHIVE" ]]; then
# Unpack architectures in parallel
UNPACK_PIDS=""
for build in "$WIN32_ARCHIVE" "$WIN_X64_ARCHIVE" "$WIN_ARM64_ARCHIVE"; do
(unzip -q "$build" && rm "$build") &
UNPACK_PIDS="$UNPACK_PIDS $!"
done
for pid in $UNPACK_PIDS; do
wait $pid
done
INCREMENTALS_FOUND=1
else
echo "$WIN32_ARCHIVE/$WIN_X64_ARCHIVE/$WIN_ARM64_ARCHIVE not found"
fi
fi
# Unpack Linux tarballs
if [ $BUILD_LINUX == 1 ]; then
# Zotero 7 has no Linux arm64 build; Zotero 11 has no Linux i686 build
LINUX_BUILDS_TO_UNPACK=("$LINUX_X86_64_ARCHIVE")
if [ "$TO_MAJOR_VERSION" -lt 11 ]; then
LINUX_BUILDS_TO_UNPACK+=("$LINUX_X86_ARCHIVE")
fi
if [ "$MAJOR_VERSION" -ge 8 ]; then
LINUX_BUILDS_TO_UNPACK+=("$LINUX_ARM64_ARCHIVE")
fi
MISSING=0
for build in "${LINUX_BUILDS_TO_UNPACK[@]}"; do
if [ ! -f "$build" ]; then
MISSING=1
break
fi
done
if [ "$MISSING" -eq 0 ]; then
# Unpack architectures in parallel
UNPACK_PIDS=""
for build in "${LINUX_BUILDS_TO_UNPACK[@]}"; do
(tar -xf "$build" && rm "$build") &
UNPACK_PIDS="$UNPACK_PIDS $!"
done
for pid in $UNPACK_PIDS; do
wait $pid
done
INCREMENTALS_FOUND=1
else
echo "Linux tarballs not found: ${LINUX_BUILDS_TO_UNPACK[*]}"
fi
fi
echo
done
# Set variables for mar command in make_(incremental|full)_update.sh
export MOZ_PRODUCT_VERSION="$TO"
export MAR_CHANNEL_ID="$CHANNEL"
# Reuse diffs and compressed files across incremental builds, since FROM
# versions often share files with each other and with the TO version. Entries
# that haven't been used recently are cleaned up above.
export UPDATE_CACHE_DIR="$ROOT_DIR/cache/update-packaging"
CHANGES_MADE=0
for build in "mac" "win32" "win-x64" "win-arm64" "linux-i686" "linux-x86_64" "linux-arm64"; do
# Zotero 7 has no Linux arm64 builds
if [[ $build == "linux-arm64" ]] && [[ $FROM == 7.* ]]; then
continue
fi
# Zotero 11 has no Linux i686 builds, so there's nothing to update to
if [[ $build == "linux-i686" ]] && [[ $TO_MAJOR_VERSION -ge 11 ]]; then
continue
fi
if [[ $build == "mac" ]]; then
if [[ $BUILD_MAC == 0 ]]; then
continue
fi
dir="Zotero.app"
else
if ([[ $build == "win32" ]] || [[ $build == "win-x64" ]] || [[ $build == "win-arm64" ]]) && [[ $BUILD_WIN == 0 ]]; then
continue
fi
if ([[ $build == "linux-i686" ]] || [[ $build == "linux-x86_64" ]] || [[ $build == "linux-arm64" ]]) && [[ $BUILD_LINUX == 0 ]]; then
continue
fi
dir="Zotero_$build"
fi
if [[ $BUILD_INCREMENTAL == 1 ]] && [[ -d "$UPDATE_STAGE_DIR/$FROM/$dir" ]]; then
echo
echo "Building incremental $build update from $FROM to $TO"
"$SCRIPT_DIR/make_incremental_update.sh" "$DIST_DIR/Zotero-${TO}-${FROM}_$build.mar" "$UPDATE_STAGE_DIR/$FROM/$dir" "$UPDATE_STAGE_DIR/$TO/$dir"
CHANGES_MADE=1
# If it's an incremental patch from a 6.0 build, use bzip instead of xz
if [[ $FROM = 6.0* ]]; then
echo "Building bzip2 version of incremental $build update from $FROM to $TO"
"$SCRIPT_DIR/xz_to_bzip" "$DIST_DIR/Zotero-${TO}-${FROM}_$build.mar" "$DIST_DIR/Zotero-${TO}-${FROM}_${build}_bz.mar"
rm "$DIST_DIR/Zotero-${TO}-${FROM}_$build.mar"
mv "$DIST_DIR/Zotero-${TO}-${FROM}_${build}_bz.mar" "$DIST_DIR/Zotero-${TO}-${FROM}_$build.mar"
fi
fi
if [[ $BUILD_FULL == 1 ]]; then
echo
echo "Building full $build update for $TO"
"$SCRIPT_DIR/make_full_update.sh" "$DIST_DIR/Zotero-${TO}-full_$build.mar" "$UPDATE_STAGE_DIR/$TO/$dir"
CHANGES_MADE=1
# Make a bzip version of all complete patches for serving to <7.0 builds. Don't bother with
# architectures that didn't exist in Z6.
#
# We can stop this once we do a waterfall build that all older versions get updated to.
if [[ $build != "win-x64" ]] && [[ $build != "win-arm64" ]]; then
echo "Building bzip2 version of full $build update for $TO"
"$SCRIPT_DIR/xz_to_bzip" "$DIST_DIR/Zotero-${TO}-full_$build.mar" "$DIST_DIR/Zotero-${TO}-full_bz_${build}.mar"
fi
fi
done
rm -rf "$UPDATE_STAGE_DIR"
# Update file manifests
if [ $CHANGES_MADE -eq 1 ]; then
# Cygwin has sha512sum, macOS has shasum, Linux has both
if [[ -n "`which sha512sum 2> /dev/null`" ]]; then
SHACMD="sha512sum"
else
SHACMD="shasum -a 512"
fi
cd "$DIST_DIR"
for platform in "mac" "win" "linux"; do
file=files-$platform
rm -f $file
for fn in `find . -name "*$platform*.mar" -exec basename {} \;`; do
size=`wc -c "$fn" | awk '{print $1}'`
hash=`$SHACMD "$fn" | awk '{print $1}'`
echo $fn $hash $size >> $file
done
done
fi

View file

@ -1,450 +0,0 @@
#!/bin/bash
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
#
# Code shared by update packaging scripts.
# Author: Darin Fisher
#
# -----------------------------------------------------------------------------
# Preserve a value set by the parent so it survives in the child processes
# spawned by run_parallel_tasks()
QUIET=${QUIET:-0}
# By default just assume that these tools exist on our path
MAR=${MAR:-mar}
MBSDIFF=${MBSDIFF:-mbsdiff}
XZ=${XZ:-xz}
$XZ --version > /dev/null 2>&1
if [ $? -ne 0 ]; then
# If $XZ is not set and not found on the path then this is probably
# running on a windows buildbot. Some of the Windows build systems have
# xz.exe in topsrcdir/xz/. Look in the places this would be in both a
# mozilla-central and comm-central build.
XZ="$(dirname "$(dirname "$(dirname "$0")")")/xz/xz.exe"
$XZ --version > /dev/null 2>&1
if [ $? -ne 0 ]; then
XZ="$(dirname "$(dirname "$(dirname "$(dirname "$0")")")")/xz/xz.exe"
$XZ --version > /dev/null 2>&1
if [ $? -ne 0 ]; then
echo "xz was not found on this system!"
echo "exiting"
exit 1
fi
fi
fi
# Ensure that we're always using the right compression settings.
# -T1 (single-threaded) is required: multi-threaded xz produces non-deterministic
# output, which would break both the reproducibility of MARs and the content-hash
# cache in process_update_task(). See get_cache_tag() for how changes here are
# accounted for in the cache.
export XZ_OPT="-T1 -7e"
# -----------------------------------------------------------------------------
# Helper routines
notice() {
echo "$*" 1>&2
}
verbose_notice() {
if [ $QUIET -eq 0 ]; then
notice "$*"
fi
}
get_file_size() {
info=($(ls -ln "$1"))
echo ${info[4]}
}
copy_perm() {
reference="$1"
target="$2"
if [ -x "$reference" ]; then
chmod 0755 "$target"
else
chmod 0644 "$target"
fi
}
make_add_instruction() {
f="$1"
filev3="$2"
# Used to log to the console
if [ $4 ]; then
forced=" (forced)"
else
forced=
fi
# Changed by Zotero for -e
is_extension=$(echo "$f" | grep -c 'distribution/extensions/.*/') || true
if [ $is_extension = "1" ]; then
# Use the subdirectory of the extensions folder as the file to test
# before performing this add instruction.
testdir=$(echo "$f" | sed 's/\(.*distribution\/extensions\/[^\/]*\)\/.*/\1/')
verbose_notice " add-if \"$testdir\" \"$f\""
echo "add-if \"$testdir\" \"$f\"" >> "$filev3"
else
verbose_notice " add \"$f\"$forced"
echo "add \"$f\"" >> "$filev3"
fi
}
check_for_add_if_not_update() {
add_if_not_file_chk="$1"
if [[ "$(basename "$add_if_not_file_chk")" = "channel-prefs.js" || \
"$add_if_not_file_chk" =~ (^|/)ChannelPrefs\.framework/ || \
"$(basename "$add_if_not_file_chk")" = "update-settings.ini" || \
"$add_if_not_file_chk" =~ (^|/)UpdateSettings\.framework/ ]]; then
## "true"
return 0;
fi
## "false"
return 1;
}
make_add_if_not_instruction() {
f="$1"
filev3="$2"
verbose_notice " add-if-not \"$f\" \"$f\""
echo "add-if-not \"$f\" \"$f\"" >> "$filev3"
}
make_patch_instruction() {
f="$1"
filev3="$2"
# Changed by Zotero for -e
is_extension=$(echo "$f" | grep -c 'distribution/extensions/.*/') || true
if [ $is_extension = "1" ]; then
# Use the subdirectory of the extensions folder as the file to test
# before performing this add instruction.
testdir=$(echo "$f" | sed 's/\(.*distribution\/extensions\/[^\/]*\)\/.*/\1/')
verbose_notice " patch-if \"$testdir\" \"$f.patch\" \"$f\""
echo "patch-if \"$testdir\" \"$f.patch\" \"$f\"" >> "$filev3"
else
verbose_notice " patch \"$f.patch\" \"$f\""
echo "patch \"$f.patch\" \"$f\"" >> "$filev3"
fi
}
append_remove_instructions() {
dir="$1"
filev3="$2"
if [ -f "$dir/removed-files" ]; then
listfile="$dir/removed-files"
elif [ -f "$dir/Contents/Resources/removed-files" ]; then
listfile="$dir/Contents/Resources/removed-files"
fi
if [ -n "$listfile" ]; then
# Changed by Zotero: Use subshell and disable filename globbing to prevent bash from expanding
# entries in removed-files with paths from the root (e.g., 'xulrunner/*')
(
set -f
# Map spaces to pipes so that we correctly handle filenames with spaces.
files=($(cat "$listfile" | tr " " "|" | sort -r))
num_files=${#files[*]}
for ((i=0; $i<$num_files; i=$i+1)); do
# Map pipes back to whitespace and remove carriage returns
f=$(echo ${files[$i]} | tr "|" " " | tr -d '\r')
# Trim whitespace
f=$(echo $f)
# Exclude blank lines.
if [ -n "$f" ]; then
# Exclude comments
if [ ! $(echo "$f" | grep -c '^#') = 1 ]; then
if [ $(echo "$f" | grep -c '/$') = 1 ]; then
verbose_notice " rmdir \"$f\""
echo "rmdir \"$f\"" >> "$filev3"
elif [ $(echo "$f" | grep -c '/\*$') = 1 ]; then
# Remove the *
f=$(echo "$f" | sed -e 's:\*$::')
verbose_notice " rmrfdir \"$f\""
echo "rmrfdir \"$f\"" >> "$filev3"
else
verbose_notice " remove \"$f\""
echo "remove \"$f\"" >> "$filev3"
fi
fi
fi
done
)
fi
}
# Return the number of parallel jobs to use for diffing/compression, from
# UPDATE_PACKAGING_JOBS or the number of cores
get_parallel_jobs() {
if [ -n "${UPDATE_PACKAGING_JOBS:-}" ]; then
echo "$UPDATE_PACKAGING_JOBS"
return 0
fi
nproc 2>/dev/null && return 0
sysctl -n hw.ncpu 2>/dev/null && return 0
echo 1
}
# Run per-file tasks from a task file in parallel by re-invoking the calling
# script with --run-task for each line. Tasks are ordered largest-file-first so
# that long-running jobs (e.g., diffing xul) start as early as possible.
#
# $1 - task file, with one "<type><TAB><relative path>" task per line
# $2 - directory to measure file sizes against for job ordering
# $3 - script to re-invoke (callers pass "$0" and handle --run-task before
# option parsing by calling process_update_task)
#
# Callers must export the variables needed by process_update_task().
run_parallel_tasks() {
local taskfile="$1"
local basedir="$2"
local script="$3"
local jobs
if [ ! -s "$taskfile" ]; then
return 0
fi
# xargs requires a resolvable command path
script="$(cd "$(dirname "$script")" && pwd)/$(basename "$script")"
# Compute the cache tag once here and export it so the per-file child
# processes inherit it rather than recomputing it for every file
if [ -n "${UPDATE_CACHE_DIR:-}" ] && [ -z "${UPDATE_CACHE_TAG:-}" ]; then
UPDATE_CACHE_TAG="$(get_cache_tag)"
export UPDATE_CACHE_TAG
fi
jobs=$(get_parallel_jobs)
notice "Processing $(wc -l < "$taskfile" | tr -d ' ') files with $jobs parallel jobs"
(cd "$basedir" && du -ak .) > "$taskfile.sizes"
awk -F'\t' 'NR==FNR { sizes[substr($2, 3)] = $1; next } { print sizes[$2] "\t" $0 }' \
"$taskfile.sizes" "$taskfile" \
| sort -rn \
| cut -f 2- \
| tr '\n' '\000' \
| xargs -0 -n 1 -P "$jobs" "$script" --run-task
}
# -----------------------------------------------------------------------------
# Diff and compression cache
#
# Building updates repeats the same expensive work: the same file contents get
# xz-compressed once per architecture, per FROM version, and per release, and
# the same before/after file pair gets binary-diffed again and again. When
# UPDATE_CACHE_DIR is set, we cache the results by content hash and reuse them
# across builds. Two kinds of entry are stored:
#
# full-<tag>-<hash>.xz A single file compressed with xz, keyed
# on the file's contents. Reused whenever
# the same content shows up again, in any
# architecture, version, or release.
#
# patch-<tag>-<oldhash>-<newhash>.xz The compressed binary diff between a
# file's old and new contents, keyed on
# both. Reused whenever the same
# before/after pair recurs (e.g., a file
# unchanged across several FROM versions
# being patched to the same TO).
#
# Both entries are written even when only one is ultimately packaged, so a file
# that loses the patch-vs-full size comparison in one build still seeds the
# cache for the next. <tag> is get_cache_tag(), so a toolchain/settings change
# starts a fresh namespace rather than reusing stale output. Entries are touched
# on use and expire via the time-based cleanup in build_autoupdate.sh.
# -----------------------------------------------------------------------------
# Print a SHA-256 content hash to use as a cache key
hash_file() {
if command -v sha256sum > /dev/null 2>&1; then
sha256sum "$1" | awk '{print $1}'
else
shasum -a 256 "$1" | awk '{print $1}'
fi
}
# Print a SHA-256 hash of stdin
hash_stdin() {
if command -v sha256sum > /dev/null 2>&1; then
sha256sum | awk '{print $1}'
else
shasum -a 256 | awk '{print $1}'
fi
}
# Print a short tag identifying the toolchain and options that produce cached
# files, so that entries are invalidated when any of them change. The cache
# keys files by input content only, on the assumption that the same inputs
# always compress/diff to the same output; this tag makes that assumption hold
# across xz/mbsdiff upgrades and XZ_OPT/BCJ_OPTIONS changes. (A change to any
# input invalidates both the full and patch caches, which is more than strictly
# necessary but keeps this simple; a stale build is just a cold rebuild.)
# Stale-tag entries are removed by the time-based cleanup in build_autoupdate.sh.
get_cache_tag() {
local mbsdiff_bin
mbsdiff_bin="$(command -v "$MBSDIFF" 2>/dev/null)"
{
$XZ --version 2>/dev/null | head -1
echo "XZ_OPT=$XZ_OPT"
echo "BCJ_OPTIONS=${BCJ_OPTIONS:-}"
# mbsdiff has no --version, so identify it by its binary contents
if [ -n "$mbsdiff_bin" ]; then
hash_file "$mbsdiff_bin"
else
echo "MBSDIFF=$MBSDIFF"
fi
} | hash_stdin | cut -c 1-16
}
# Atomically store file $2 in the cache as $1
cache_store() {
mkdir -p "$(dirname "$1")"
cp "$2" "$1.tmp.$$" && mv -f "$1.tmp.$$" "$1"
}
# xz-compress $1 to $2, reusing a cached result when one exists (see the cache
# overview above)
compress_full_file() {
local src="$1"
local dest="$2"
local key=""
if [ -n "${UPDATE_CACHE_DIR:-}" ]; then
key="$UPDATE_CACHE_DIR/full-${UPDATE_CACHE_TAG:-}-$(hash_file "$src").xz"
if [ -f "$key" ]; then
# Keep entries that are still in use from expiring
touch -c "$key" 2>/dev/null || true
cp "$key" "$dest"
return 0
fi
fi
$XZ $XZ_OPT --compress $BCJ_OPTIONS --lzma2 --format=xz --check=crc64 --force --stdout "$src" > "$dest"
if [ -n "$key" ]; then
cache_store "$key" "$dest"
fi
}
# Process a single task line from run_parallel_tasks():
#
# full - compress the new file into the work directory
# diff - if the file changed, generate a binary diff and keep the smaller of
# the compressed patch ($f.patch) and the compressed file ($f)
#
# Expects newdir and workdir in the environment, plus olddir for diff tasks.
# The results are assembled into the manifest serially by the caller based on
# which files exist in the work directory. Diffs and compressed files are
# cached when enabled -- see the cache overview above.
process_update_task() {
local task="$1"
local tab=$(printf '\t')
local type="${task%%"$tab"*}"
local f="${task#*"$tab"}"
local oldfile_path newfile_path patch_path patchsize fullsize full_pid patchkey
if [ "$type" = "diff" ]; then
if diff "$olddir/$f" "$newdir/$f" > /dev/null; then
# Unchanged
return 0
fi
mkdir -p "$(dirname "$workdir/$f")"
verbose_notice "diffing \"$f\""
# Compress the full new file in the background while diffing, since both
# are needed to decide which to package
compress_full_file "$newdir/$f" "$workdir/$f" &
full_pid=$!
patchkey=""
if [ -n "${UPDATE_CACHE_DIR:-}" ]; then
patchkey="$UPDATE_CACHE_DIR/patch-${UPDATE_CACHE_TAG:-}-$(hash_file "$olddir/$f")-$(hash_file "$newdir/$f").xz"
fi
if [ -n "$patchkey" ] && [ -f "$patchkey" ]; then
# Keep entries that are still in use from expiring
touch -c "$patchkey" 2>/dev/null || true
cp "$patchkey" "$workdir/$f.patch.xz"
else
# mbsdiff doesn't like POSIX paths on Windows
if [ ${WIN_NATIVE:-0} -eq 1 ]; then
oldfile_path=$(cygpath -m "$olddir/$f")
newfile_path=$(cygpath -m "$newdir/$f")
patch_path=$(cygpath -m "$workdir/$f.patch")
else
oldfile_path="$olddir/$f"
newfile_path="$newdir/$f"
patch_path="$workdir/$f.patch"
fi
$MBSDIFF "$oldfile_path" "$newfile_path" "$patch_path"
$XZ $XZ_OPT --compress --lzma2 --format=xz --check=crc64 --force "$workdir/$f.patch"
if [ -n "$patchkey" ]; then
cache_store "$patchkey" "$workdir/$f.patch.xz"
fi
fi
wait $full_pid
copy_perm "$newdir/$f" "$workdir/$f"
patchsize=$(get_file_size "$workdir/$f.patch.xz")
fullsize=$(get_file_size "$workdir/$f")
if [ $patchsize -lt $fullsize ]; then
mv -f "$workdir/$f.patch.xz" "$workdir/$f.patch"
rm -f "$workdir/$f"
else
rm -f "$workdir/$f.patch.xz"
fi
else
mkdir -p "$(dirname "$workdir/$f")"
compress_full_file "$newdir/$f" "$workdir/$f"
copy_perm "$newdir/$f" "$workdir/$f"
fi
}
# List all files in the current directory, stripping leading "./"
# Pass a variable name and it will be filled as an array.
list_files() {
count=0
temp_filelist=$(mktemp)
find . -type f \
! -name "update.manifest" \
! -name "updatev2.manifest" \
! -name "updatev3.manifest" \
| sed 's/\.\/\(.*\)/\1/' \
| sort -r > "${temp_filelist}"
while read file; do
eval "${1}[$count]=\"$file\""
# Changed for Zotero to avoid eval as 1
#(( count++ ))
(( ++count ))
done < "${temp_filelist}"
rm "${temp_filelist}"
}
# List all directories in the current directory, stripping leading "./"
list_dirs() {
count=0
temp_dirlist=$(mktemp)
find . -type d \
! -name "." \
! -name ".." \
| sed 's/\.\/\(.*\)/\1/' \
| sort -r > "${temp_dirlist}"
while read dir; do
eval "${1}[$count]=\"$dir\""
# Changed for Zotero
#(( count++ ))
(( ++count ))
done < "${temp_dirlist}"
rm "${temp_dirlist}"
}

View file

@ -1,145 +0,0 @@
#!/bin/bash
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
#
# This tool generates full update packages for the update system.
# Author: Darin Fisher
#
# Added for Zotero
set -eo pipefail
. $(dirname "$0")/common.sh
# Process a single file task when invoked from run_parallel_tasks()
if [ "${1:-}" = "--run-task" ]; then
process_update_task "$2"
exit 0
fi
# -----------------------------------------------------------------------------
print_usage() {
notice "Usage: $(basename $0) [OPTIONS] ARCHIVE DIRECTORY"
}
if [ $# = 0 ]; then
print_usage
exit 1
fi
if [ $1 = -h ]; then
print_usage
notice ""
notice "The contents of DIRECTORY will be stored in ARCHIVE."
notice ""
notice "Options:"
notice " -h show this help text"
notice " -q be less verbose"
notice ""
exit 1
fi
if [ $1 = -q ]; then
QUIET=1
export QUIET
shift
fi
# -----------------------------------------------------------------------------
mar_command="$MAR -V ${MOZ_PRODUCT_VERSION:?} -H ${MAR_CHANNEL_ID:?}"
archive="$1"
targetdir="$2"
# Prevent the workdir from being inside the targetdir so it isn't included in
# the update mar.
if [ $(echo "$targetdir" | grep -c '/$') = 1 ]; then
# Remove the /
targetdir=$(echo "$targetdir" | sed -e 's:\/$::')
fi
workdir="$targetdir.work"
updatemanifestv3="$workdir/updatev3.manifest"
targetfiles="updatev3.manifest"
mkdir -p "$workdir"
# Generate a list of all files in the target directory.
pushd "$targetdir"
if test $? -ne 0 ; then
exit 1
fi
if [ ! -f "precomplete" ]; then
if [ ! -f "Contents/Resources/precomplete" ]; then
notice "precomplete file is missing!"
exit 1
fi
fi
list_files files
popd
# Add the type of update to the beginning of the update manifests.
> "$updatemanifestv3"
notice ""
notice "Adding type instruction to update manifests"
notice " type complete"
echo "type \"complete\"" >> "$updatemanifestv3"
notice ""
notice "Adding file add instructions to update manifests"
num_files=${#files[*]}
# Compress the files in parallel via run_parallel_tasks() in
# common.sh, and then assemble the manifest and archive list serially in the
# original order
tmpdir="$(mktemp -d)"
taskfile="$tmpdir/tasks"
TAB="$(printf '\t')"
> "$taskfile"
for ((i=0; $i<$num_files; i=$i+1)); do
echo "full$TAB${files[$i]}" >> "$taskfile"
done
newdir="$targetdir"
export newdir workdir BCJ_OPTIONS QUIET
run_parallel_tasks "$taskfile" "$targetdir" "$0"
rm -rf "$tmpdir"
for ((i=0; $i<$num_files; i=$i+1)); do
f="${files[$i]}"
if check_for_add_if_not_update "$f"; then
make_add_if_not_instruction "$f" "$updatemanifestv3"
else
make_add_instruction "$f" "$updatemanifestv3"
fi
targetfiles="$targetfiles \"$f\""
done
# Append remove instructions for any dead files.
notice ""
notice "Adding file and directory remove instructions from file 'removed-files'"
append_remove_instructions "$targetdir" "$updatemanifestv3"
$XZ $XZ_OPT --compress $BCJ_OPTIONS --lzma2 --format=xz --check=crc64 --force "$updatemanifestv3" && mv -f "$updatemanifestv3.xz" "$updatemanifestv3"
# Changed for Zotero -- -C is unreliable
pushd "$workdir" > /dev/null
mar_command="$mar_command -c output.mar"
eval "$mar_command $targetfiles"
popd > /dev/null
mv -f "$workdir/output.mar" "$archive"
# cleanup
rm -fr "$workdir"
notice ""
notice "Finished"
notice ""

View file

@ -1,301 +0,0 @@
#!/bin/bash
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
#
# This tool generates incremental update packages for the update system.
# Author: Darin Fisher
#
# Added for Zotero
set -eo pipefail
. $(dirname "$0")/common.sh
# Process a single file task when invoked from run_parallel_tasks()
if [ "${1:-}" = "--run-task" ]; then
process_update_task "$2"
exit 0
fi
# -----------------------------------------------------------------------------
print_usage() {
notice "Usage: $(basename $0) [OPTIONS] ARCHIVE FROMDIR TODIR"
notice ""
notice "The differences between FROMDIR and TODIR will be stored in ARCHIVE."
notice ""
notice "Options:"
notice " -h show this help text"
notice " -f clobber this file in the installation"
notice " Must be a path to a file to clobber in the partial update."
notice " -q be less verbose"
notice ""
}
check_for_forced_update() {
force_list="$1"
forced_file_chk="$2"
local f
if [ "$forced_file_chk" = "precomplete" ]; then
## "true" *giggle*
return 0;
fi
if [ "$forced_file_chk" = "Contents/Resources/precomplete" ]; then
## "true" *giggle*
return 0;
fi
if [ "$forced_file_chk" = "removed-files" ]; then
## "true" *giggle*
return 0;
fi
if [ "$forced_file_chk" = "Contents/Resources/removed-files" ]; then
## "true" *giggle*
return 0;
fi
# notarization ticket
if [ "$forced_file_chk" = "Contents/CodeResources" ]; then
## "true" *giggle*
return 0;
fi
if [ "${forced_file_chk##*.}" = "chk" ]; then
## "true" *giggle*
return 0;
fi
for f in $force_list; do
#echo comparing $forced_file_chk to $f
if [ "$forced_file_chk" = "$f" ]; then
## "true" *giggle*
return 0;
fi
done
## 'false'... because this is bash. Oh yay!
return 1;
}
if [ $# = 0 ]; then
print_usage
exit 1
fi
requested_forced_updates='Contents/MacOS/firefox'
while getopts "hqf:" flag
do
case "$flag" in
h) print_usage; exit 0
;;
q) QUIET=1
;;
f) requested_forced_updates="$requested_forced_updates $OPTARG"
;;
?) print_usage; exit 1
;;
esac
done
# -----------------------------------------------------------------------------
mar_command="$MAR -V ${MOZ_PRODUCT_VERSION:?} -H ${MAR_CHANNEL_ID:?}"
# Added for -e for Zotero
set +e
let arg_start=$OPTIND-1
shift $arg_start
set -e
archive="$1"
olddir="$2"
newdir="$3"
# Prevent the workdir from being inside the targetdir so it isn't included in
# the update mar.
if [ $(echo "$newdir" | grep -c '/$') = 1 ]; then
# Remove the /
newdir=$(echo "$newdir" | sed -e 's:\/$::')
fi
workdir="$(mktemp -d)"
updatemanifestv3="$workdir/updatev3.manifest"
archivefiles="updatev3.manifest"
mkdir -p "$workdir"
# Generate a list of all files in the target directory.
pushd "$olddir"
if test $? -ne 0 ; then
exit 1
fi
list_files oldfiles
list_dirs olddirs
popd
pushd "$newdir"
if test $? -ne 0 ; then
exit 1
fi
if [ ! -f "precomplete" ]; then
if [ ! -f "Contents/Resources/precomplete" ]; then
notice "precomplete file is missing!"
exit 1
fi
fi
list_dirs newdirs
list_files newfiles
popd
# Add the type of update to the beginning of the update manifests.
notice ""
notice "Adding type instruction to update manifests"
> $updatemanifestv3
notice " type partial"
echo "type \"partial\"" >> $updatemanifestv3
notice ""
notice "Adding file patch and add instructions to update manifests"
num_oldfiles=${#oldfiles[*]}
remove_array=
num_removes=0
# The main file loop is split into three passes so that the
# CPU-heavy work can run in parallel: classify each file into a task list, run
# the diffing/compression tasks in parallel via run_parallel_tasks() in
# common.sh, and then assemble the manifest and archive list serially in the
# original order based on the files the tasks left in the work directory.
#
# (This also drops the unused MBSDIFF_HOOK/funsize path from the upstream
# script -- the diff behavior itself is unchanged and now lives in
# process_update_task() in common.sh.)
tmpdir="$(mktemp -d)"
taskfile="$tmpdir/tasks"
TAB="$(printf '\t')"
> "$taskfile"
for ((i=0; $i<$num_oldfiles; i=$i+1)); do
f="${oldfiles[$i]}"
# If this file exists in the new directory as well, then check if it differs.
if [ -f "$newdir/$f" ]; then
if check_for_add_if_not_update "$f"; then
echo "full$TAB$f" >> "$taskfile"
elif check_for_forced_update "$requested_forced_updates" "$f"; then
echo "full$TAB$f" >> "$taskfile"
else
echo "diff$TAB$f" >> "$taskfile"
fi
fi
done
# Newly added files -- in the new directory but not the old one. (This replaces
# the O(n^2) nested skip loop from the upstream script.)
printf '%s\n' "${oldfiles[@]}" | sort > "$tmpdir/oldlist"
printf '%s\n' "${newfiles[@]}" | sort > "$tmpdir/newlist"
comm -13 "$tmpdir/oldlist" "$tmpdir/newlist" | sed '/^$/d' | sort -r > "$tmpdir/newonly"
while IFS= read -r f; do
echo "full$TAB$f" >> "$taskfile"
done < "$tmpdir/newonly"
export olddir newdir workdir MBSDIFF BCJ_OPTIONS QUIET
run_parallel_tasks "$taskfile" "$newdir" "$0"
# Assemble the manifest and archive list in the original order. A diffed file
# left $f.patch in the work directory if the patch was smaller, $f if the
# compressed file was smaller, and neither if the file was unchanged.
for ((i=0; $i<$num_oldfiles; i=$i+1)); do
f="${oldfiles[$i]}"
if [ -f "$newdir/$f" ]; then
if check_for_add_if_not_update "$f"; then
make_add_if_not_instruction "$f" "$updatemanifestv3"
archivefiles="$archivefiles \"$f\""
elif check_for_forced_update "$requested_forced_updates" "$f"; then
make_add_instruction "$f" "$updatemanifestv3" 1
archivefiles="$archivefiles \"$f\""
elif [ -f "$workdir/$f.patch" ]; then
make_patch_instruction "$f" "$updatemanifestv3"
archivefiles="$archivefiles \"$f.patch\""
elif [ -f "$workdir/$f" ]; then
make_add_instruction "$f" "$updatemanifestv3"
archivefiles="$archivefiles \"$f\""
fi
else
# remove instructions are added after add / patch instructions for
# consistency with make_incremental_updates.py
remove_array[$num_removes]=$f
# Changed by Zotero for -e
#(( num_removes++ ))
(( ++num_removes ))
fi
done
# Newly added files
notice ""
notice "Adding file add instructions to update manifests"
while IFS= read -r f; do
if check_for_add_if_not_update "$f"; then
make_add_if_not_instruction "$f" "$updatemanifestv3"
else
make_add_instruction "$f" "$updatemanifestv3"
fi
archivefiles="$archivefiles \"$f\""
done < "$tmpdir/newonly"
rm -rf "$tmpdir"
notice ""
notice "Adding file remove instructions to update manifests"
for ((i=0; $i<$num_removes; i=$i+1)); do
f="${remove_array[$i]}"
verbose_notice " remove \"$f\""
echo "remove \"$f\"" >> $updatemanifestv3
done
# Add remove instructions for any dead files.
notice ""
notice "Adding file and directory remove instructions from file 'removed-files'"
append_remove_instructions "$newdir" "$updatemanifestv3"
notice ""
notice "Adding directory remove instructions for directories that no longer exist"
num_olddirs=${#olddirs[*]}
for ((i=0; $i<$num_olddirs; i=$i+1)); do
f="${olddirs[$i]}"
# If this dir doesn't exist in the new directory remove it.
if [ ! -d "$newdir/$f" ]; then
verbose_notice " rmdir $f/"
echo "rmdir \"$f/\"" >> $updatemanifestv3
fi
done
$XZ $XZ_OPT --compress $BCJ_OPTIONS --lzma2 --format=xz --check=crc64 --force "$updatemanifestv3" && mv -f "$updatemanifestv3.xz" "$updatemanifestv3"
# Changed for Zotero -- -C is unreliable
pushd "$workdir" > /dev/null
mar_command="$mar_command -c output.mar"
eval "$mar_command $archivefiles"
popd > /dev/null
mv -f "$workdir/output.mar" "$archive"
# cleanup
rm -fr "$workdir"
notice ""
notice "Finished"
notice ""

View file

@ -1,24 +0,0 @@
application.ini
chrome.manifest
chrome/*
components/*
defaults/*
deleted.txt
dictionaries/*
extensions/*
fonts/EmojiOneMozilla.ttf
gtk2/*
icudt58l.dat
install.rdf
libnssdbm3.chk
libnssdbm3.so
libsoftokn3.chk
pingsender
resource/*
run-zotero.sh
styles.zip
test/*
translators.index
translators.zip
xulrunner/*
zotero.jar

View file

@ -1,67 +0,0 @@
Contents/Frameworks/XUL.framework/
Contents/MacOS/Info.plist
Contents/MacOS/LICENSE
Contents/MacOS/README.xulrunner
Contents/MacOS/Resources/*
Contents/MacOS/active-update.xml
Contents/MacOS/chrome.manifest
Contents/MacOS/components/
Contents/MacOS/crashreporter.app/*
Contents/MacOS/defaults/*
Contents/MacOS/dependentlibs.list
Contents/MacOS/dictionaries/
Contents/MacOS/gmp-fake/*
Contents/MacOS/js-gdb.py
Contents/MacOS/libc++.1.dylib
Contents/MacOS/libfreebl.chk
Contents/MacOS/libmozsqlite3.dylib
Contents/MacOS/libnspr4.dylib
Contents/MacOS/libnssdbm3.chk
Contents/MacOS/libnssdbm3.dylib
Contents/MacOS/libnssutil3.dylib
Contents/MacOS/libplc4.dylib
Contents/MacOS/libplds4.dylib
Contents/MacOS/libplugin_child_interpose.dylib
Contents/MacOS/libsmime3.dylib
Contents/MacOS/libsoftokn3.chk
Contents/MacOS/libssl3.dylib
Contents/MacOS/libxpcom.dylib
Contents/MacOS/omni.ja
Contents/MacOS/pdfinfo
Contents/MacOS/pdftotext
Contents/MacOS/pingsender
Contents/MacOS/platform.ini
Contents/MacOS/precomplete
Contents/MacOS/res/*
Contents/MacOS/update-settings.ini
Contents/MacOS/updater.app/Contents/MacOS/updater-bin
Contents/MacOS/updates.xml
Contents/MacOS/updates/*
Contents/MacOS/zotero-bin
Contents/Resources/CONTRIBUTING.md
Contents/Resources/COPYING
Contents/Resources/README.md
Contents/Resources/application.ini
Contents/Resources/chrome.manifest
Contents/Resources/chrome/*
Contents/Resources/components/*
Contents/Resources/defaults/*
Contents/Resources/deleted.txt
Contents/Resources/devtools.jar
Contents/Resources/dictionaries/*
Contents/Resources/extensions/*
Contents/Resources/gmp-clearkey/0.1/clearkey.info
Contents/Resources/icudt56l.dat
Contents/Resources/install.rdf
Contents/Resources/poppler-data/*
Contents/Resources/resource/*
Contents/Resources/styles.zip
Contents/Resources/test/*
Contents/Resources/translators.index
Contents/Resources/translators.zip
Contents/Resources/voucher.bin
Contents/Resources/zotero.jar
Contents/XPCServices/*
Contents/_CodeSignature/CodeDirectory
Contents/_CodeSignature/CodeRequirements
Contents/_CodeSignature/CodeSignature

View file

@ -1,58 +0,0 @@
Accessible.tlb
AccessibleHandler.dll
IA2Marshal.dll
Microsoft.VC80.CRT.manifest
api-ms-win-core-console-l1-1-0.dll
api-ms-win-core-datetime-l1-1-0.dll
api-ms-win-core-debug-l1-1-0.dll
api-ms-win-core-errorhandling-l1-1-0.dll
api-ms-win-core-file-l1-1-0.dll
api-ms-win-core-handle-l1-1-0.dll
api-ms-win-core-heap-l1-1-0.dll
api-ms-win-core-interlocked-l1-1-0.dll
api-ms-win-core-libraryloader-l1-1-0.dll
api-ms-win-core-memory-l1-1-0.dll
api-ms-win-core-namedpipe-l1-1-0.dll
api-ms-win-core-processenvironment-l1-1-0.dll
api-ms-win-core-processthreads-l1-1-0.dll
api-ms-win-core-profile-l1-1-0.dll
api-ms-win-core-rtlsupport-l1-1-0.dll
api-ms-win-core-string-l1-1-0.dll
api-ms-win-core-synch-l1-1-0.dll
api-ms-win-core-sysinfo-l1-1-0.dll
api-ms-win-core-util-l1-1-0.dll
application.ini
chrome.manifest
chrome/*
components/*
defaults/*
deleted.txt
dictionaries/*
extensions/*
firefox.*
fonts/EmojiOneMozilla.ttf
freebl3.chk
gkmedias.dll
install.rdf
minidump-analyzer.exe
mozcrt19.dll
mozutils.dll
msvcp80.dll
msvcp120.dll
msvcr80.dll
msvcr120.dll
nssdbm3.chk
nssdbm3.dll
pdfinfo.exe
pdftotext.exe
pingsender.exe
plugin-hang-ui.exe
poppler-data/*
resource/*
softokn3.chk
styles.zip
test/*
translators.index
translators.zip
xulrunner/*
zotero.jar

View file

@ -1,66 +0,0 @@
#!/bin/bash
set -euo pipefail
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
APP_ROOT_DIR="$(dirname "$SCRIPT_DIR")"
. "$APP_ROOT_DIR/config.sh"
infile=${1:-}
outfile=${2:-}
if [[ -z "$infile" ]] || [[ -z "$infile" ]]; then
echo "Usage: $0 infile.mar outfile.mar"
exit 1
fi
mar="$APP_ROOT_DIR/xulrunner/bin/mar"
if [ ! -f "$mar" ]; then
echo "$mar not found"
exit 1
fi
tmp_dir=`mktemp -d`
function cleanup {
rm -rf $tmp_dir
}
trap cleanup EXIT
cd "$tmp_dir"
mkdir in
cd in
if [ "`uname -o 2> /dev/null`" = "Cygwin" ]; then
infile=$(cygpath -w "$infile")
outfile=$(cygpath -w "$outfile")
fi
echo "Extracting MAR"
$mar -x "$infile"
echo "Renaming all files to .xz"
find . -type f -exec mv {} {}.xz \;
echo "Uncompressing files"
find . -type f -exec unxz {} \;
echo "Recompressing files with bzip2"
find . -type f -exec bzip2 {} \;
echo "Removing .bz extension"
find . -type f | while read f; do mv "$f" "${f%.bz2}"; done
channel=$($mar -T "$infile" | sed -n -r 's/.+MAR channel name: ([^\s]+)/\1/p')
version=$($mar -T "$infile" | sed -n -r 's/.+Product version: ([^\s]+)/\1/p')
if [ -z "$channel" ]; then
echo "Could not detect channel"
exit 1
fi
if [ -z "$version" ]; then
echo "Could not detect version"
exit 1
fi
echo "MAR channel name: $channel"
echo "Product version: $version"
echo "Creating new MAR"
find . -type f -print0 | xargs -0 $mar -V $version -H $channel -c "$outfile"
echo
$mar -T "$outfile"

Binary file not shown.

Binary file not shown.

View file

@ -1,59 +0,0 @@
#!/bin/bash
set -euo pipefail
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
APP_ROOT_DIR="$(dirname "$SCRIPT_DIR")"
. "$APP_ROOT_DIR/config.sh"
if [ $# -lt 2 ]; then
echo "Usage: $0 /path/to/src/firefox x64|arm64|win32" >&2
exit 1
fi
gecko_path=$1
arch=$2
if [ ! -d "$gecko_path" ]; then
echo "$gecko_path is not a directory" >&2
exit 1
fi
# Install required Rust version
rustup toolchain install $RUST_VERSION
if [ $arch = "x64" ]; then
rust_target=x86_64
elif [ $arch = "arm64" ]; then
rust_target=aarch64
elif [ $arch = "win32" ]; then
rust_target=i686
else
echo "Unknown architecture $arch" >&2
exit 1
fi
rustup default $RUST_VERSION
rustup target add $rust_target-pc-windows-msvc
cp "$SCRIPT_DIR/mozconfig" "$gecko_path"
if [[ $arch == "arm64" || $arch == "win32" ]]; then
export Z_ARCH=$arch
export RUST_TARGET=$rust_target-pc-windows-msvc
fi
cd "$gecko_path"
./mach build
./mach package
# Copy the packaged ZIP back to app/win/ for launcher/xul.dll extraction
case $arch in
x64) zip_suffix=win64 ;;
arm64) zip_suffix=win64-aarch64 ;;
win32) zip_suffix=win32 ;;
esac
zip_file=$(ls "$gecko_path"/obj-*/dist/firefox-*.en-US.${zip_suffix}.zip 2>/dev/null | head -1) || true
if [ -z "$zip_file" ] || [ ! -f "$zip_file" ]; then
echo "Could not find packaged zip for $arch in $gecko_path/obj-*/dist/" >&2
exit 1
fi
cp "$zip_file" "$SCRIPT_DIR/"
echo "Copied $(basename "$zip_file") to $SCRIPT_DIR"

View file

@ -1,59 +0,0 @@
#!/bin/bash
set -euo pipefail
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
ROOT_DIR="$(dirname "$SCRIPT_DIR")"
. "$ROOT_DIR/config.sh"
#
# Turns out we need older versions from Mozilla, not the official ZIPs
#
#plugins=$(cat <<EOF
#http://nsis.sourceforge.net/mediawiki/images/d/d4/AppAssocReg-0.4.zip
#https://github.com/connectiblutz/NSIS-ApplicationID/releases/download/1.1/NSIS-ApplicationID.zip
#http://nsis.sourceforge.net/mediawiki/images/c/ca/InvokeShellVerb-1.0.zip
#http://nsis.sourceforge.net/mediawiki/images/6/6c/Shelllink.zip
#http://nsis.sourceforge.net/mediawiki/images/8/8f/UAC.zip
#EOF
#)
#
#mkdir -p nsis
#cd nsis
#for plugin in $plugins; do
# curl -fsSLO $plugin
#done
#
#unzip_cmd="unzip -d Plugins -j"
#for zip in AppAssocReg*.zip InvokeShellVerb*.zip; do
# $unzip_cmd $zip 'Plugins/Unicode/*.dll'
#done
#$unzip_cmd Shelllink*.zip Unicode/Plugins/ShellLink.dll
#$unzip_cmd NSIS-ApplicationID*.zip 'ReleaseUnicode/ApplicationID*'
#$unzip_cmd UAC.zip Plugins/x86-unicode/UAC.dll
#
#rm *.zip
#
#echo
#echo
#echo "Files extracted to ./nsis/Plugins -- move to ${NSIS_DIR}Plugins"
#echo
#ls -la Plugins
mkdir -p Plugins
cd Plugins
plugins="AccessControl AppAssocReg ApplicationID InvokeShellVerb ShellLink UAC"
for plugin in $plugins; do
curl https://hg.mozilla.org/mozilla-central/raw-file/052d53200cf8/other-licenses/nsis/Plugins/$plugin.dll > $plugin.dll
done
# From https://nsis.sourceforge.io/NsProcess_plugin
curl https://download.zotero.org/dev/win/NsProcess-1.6.zip > NsProcess.zip
7z e NsProcess.zip "Plugin/nsProcessW.dll"
mv nsProcessW.dll nsProcess.dll
rm NsProcess.zip
echo
echo
echo "Files downloaded to ./Plugins -- move to ${NSIS_DIR}Plugins"
echo
ls -la

View file

@ -1,84 +0,0 @@
#!/bin/bash
#
# Extract xul.dll from custom Firefox build ZIPs in current folder and create a
# ZIP for each platform with its own SHA256 hash in the filename. The files
# should then be uploaded and their hashes updated in config.sh so that
# fetch_xulrunner will download and use the custom xul.dll.
set -euo pipefail
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
cd "$SCRIPT_DIR"
if [ $# -ne 1 ]; then
echo "Usage: $0 <version>"
exit 1
fi
version="$1"
# Input ZIP filenames
files=(
"firefox-$version.en-US.win32.zip"
"firefox-$version.en-US.win64-aarch64.zip"
"firefox-$version.en-US.win64.zip"
)
# Corresponding architecture labels and output names
arches=(
"win32"
"arm64"
"x64"
)
# Platform-specific SHA command
if [[ "$(uname)" = "Darwin" ]]; then
shasum_cmd="shasum -a 256"
else
shasum_cmd="sha256sum"
fi
# Clean up any old artifacts
rm -f "$version"-*.zip
# Process whichever arch ZIPs are present
processed=0
for i in "${!files[@]}"; do
file="${files[$i]}"
arch="${arches[$i]}"
temp_zip="xul-temp-$arch.zip"
if [ ! -f "$file" ]; then
continue
fi
dlls=(xul.dll)
# TEMP: Fix startup error on win32 due to missing export numSamples@RLBoxSoundTouch
if [[ $arch == "win32" ]]; then
dlls+=(lgpllibs.dll)
fi
echo "Extracting ${dlls[*]} from $file"
for dll in "${dlls[@]}"; do
unzip -p "$file" "firefox/$dll" > "$dll"
done
zip -q "$temp_zip" "${dlls[@]}"
# Calculate hash
sum=$($shasum_cmd "$temp_zip" | awk '{print $1}')
# Rename to final output
final_zip="$version-$arch-$sum.zip"
mv "$temp_zip" "$final_zip"
rm -f xul.dll lgpllibs.dll
echo "Created $final_zip"
processed=$((processed + 1))
done
if [ $processed -eq 0 ]; then
echo "No firefox-$version.en-US.*.zip files found in $SCRIPT_DIR" >&2
exit 1
fi

View file

@ -1,3 +0,0 @@
// CompressionMethod.cpp
#include "StdAfx.h"

View file

@ -1,64 +0,0 @@
// 7zCompressionMode.h
#ifndef __7Z_COMPRESSION_MODE_H
#define __7Z_COMPRESSION_MODE_H
#include "../../../Windows/PropVariant.h"
#include "7zMethodID.h"
namespace NArchive {
namespace N7z {
struct CProperty
{
PROPID PropID;
NWindows::NCOM::CPropVariant Value;
};
struct CMethodFull
{
CMethodID MethodID;
UInt32 NumInStreams;
UInt32 NumOutStreams;
bool IsSimpleCoder() const
{ return (NumInStreams == 1) && (NumOutStreams == 1); }
#ifdef EXCLUDE_COM
#else
CLSID EncoderClassID;
CSysString FilePath;
#endif
CObjectVector<CProperty> CoderProperties;
};
struct CBind
{
UInt32 InCoder;
UInt32 InStream;
UInt32 OutCoder;
UInt32 OutStream;
};
struct CCompressionMethodMode
{
CObjectVector<CMethodFull> Methods;
CRecordVector<CBind> Binds;
#ifdef COMPRESS_MT
UInt32 NumThreads;
#endif
bool PasswordIsDefined;
UString Password;
bool IsEmpty() const { return (Methods.IsEmpty() && !PasswordIsDefined); }
CCompressionMethodMode(): PasswordIsDefined(false)
#ifdef COMPRESS_MT
, NumThreads(1)
#endif
{}
};
}}
#endif

Some files were not shown because too many files have changed in this diff Show more