build/macos, plug-ins: Generate file associations for macOS automatically
Following2ce3c604(for Windows) andd56676a2(for Linux) To make this possible the generate_mime_ext.py internals were changed to construct a dictionary instead of a list like before, because macOS supports both extension and mimetype (and also UTI).
This commit is contained in:
parent
c71c160866
commit
0e2f0f6880
6 changed files with 132 additions and 20 deletions
|
|
@ -706,6 +706,7 @@ gimp-macos-inhouse:
|
|||
- _build*/done-dylib.list
|
||||
# Needed by dist-mac-weekly
|
||||
- _build-*/config.h
|
||||
- _build-*/plug-ins/file_associations_mac.list
|
||||
- _build-*/gimp-data/images/logo/gimp-dmg.png
|
||||
expire_in: 2 days
|
||||
|
||||
|
|
|
|||
|
|
@ -141,6 +141,8 @@ shutil.copy2(Path(f"{GIMP_SOURCE}/build/macos/Info.plist"), GIMP_DISTRIB)
|
|||
### FIXME: Icon (generate Assets.car for Liquid Glass)
|
||||
(GIMP_DISTRIB / "Resources").mkdir(parents=True, exist_ok=True)
|
||||
shutil.copy2(Path(f"{os.getenv('MESON_BUILD_ROOT')}/gimp-data/images/logo/gimp.icns"), GIMP_DISTRIB / "Resources/AppIcon.icns")
|
||||
shutil.copy2(Path(f"{os.getenv('MESON_BUILD_ROOT')}/build/macos/fileicon-xcf.icns"), GIMP_DISTRIB / "Resources/fileicon-xcf.icns")
|
||||
shutil.copy2(Path(f"{os.getenv('MESON_BUILD_ROOT')}/build/macos/fileicon.icns"), GIMP_DISTRIB / "Resources/fileicon.icns")
|
||||
|
||||
|
||||
## BUNDLE BASE (BARE MINIMUM TO RUN GTK APPS).
|
||||
|
|
|
|||
|
|
@ -130,7 +130,8 @@ conf_plist "%BUNDLE_NAME%" "$BUNDLE_NAME"
|
|||
conf_plist "%GIMP_VERSION%" "$CUSTOM_GIMP_VERSION"
|
||||
#### Needed to differentiate on zsh etc
|
||||
conf_plist "%MUTEX_SUFFIX%" "$MUTEX_SUFFIX"
|
||||
### FIXME: Configure associations
|
||||
### List supported filetypes
|
||||
sed -i '' "s|%FILE_TYPES%|$(tr -d '\n' < $BUILD_DIR/plug-ins/file_associations_mac.list)|g" "$DMG_MOUNT/$BUNDLE_NAME.app/Contents/Info.plist"
|
||||
|
||||
## 4.2 FIXME: Create .DS_Store to set .dmg background and icon layout
|
||||
printf '(INFO): generating .DS_Store\n'
|
||||
|
|
|
|||
|
|
@ -39,5 +39,30 @@
|
|||
<false/>
|
||||
<key>NLSRequiresNativeExecution</key>
|
||||
<true/>
|
||||
<key>CFBundleDocumentTypes</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>CFBundleTypeExtensions</key>
|
||||
<array>
|
||||
<string>xcf</string>
|
||||
<string>XCF</string>
|
||||
</array>
|
||||
<key>CFBundleTypeMIMETypes</key>
|
||||
<array>
|
||||
<string>image/x-xcf</string>
|
||||
</array>
|
||||
<key>CFBundleTypeIconFiles</key>
|
||||
<array>
|
||||
<string>fileicon-xcf.icns</string>
|
||||
</array>
|
||||
<key>CFBundleTypeName</key>
|
||||
<string>eXperimental Computing Facility file</string>
|
||||
<key>CFBundleTypeRole</key>
|
||||
<string>Editor</string>
|
||||
<key>LSHandlerRank</key>
|
||||
<string>Default</string>
|
||||
</dict>
|
||||
%FILE_TYPES%
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import sys
|
|||
import os
|
||||
import re
|
||||
|
||||
types_associations_list = set()
|
||||
types_associations_dict = {}
|
||||
|
||||
#Read file loading plug-ins sourcecode
|
||||
source_files = sys.argv[3:]
|
||||
|
|
@ -16,39 +16,108 @@ for source_file in source_files:
|
|||
continue
|
||||
|
||||
#Parse MIME types or extensions declared in the sourcecode
|
||||
mode = sys.argv[1]
|
||||
if mode == "--mime":
|
||||
function_suffix = 'set_mime_types'
|
||||
elif mode == "--association":
|
||||
function_suffix = 'set_extensions'
|
||||
source_file_ext = os.path.splitext(source_file)[1].lower()
|
||||
if source_file_ext == '.c':
|
||||
if "LOAD_PROC" not in content and "load_procedure" not in content:
|
||||
continue
|
||||
regex = (fr'gimp_file_procedure_{function_suffix}\s*'
|
||||
fr'\(\s*GIMP_FILE_PROCEDURE\s*\(\s*procedure\s*\)\s*,\s*"([^"]+)"')
|
||||
proc_regex = r'gimp_(load|vector_load)_procedure_new'
|
||||
mime_regex = r'gimp_file_procedure_set_mime_types\s*\([^,]+,\s*"([^"]+)"'
|
||||
ext_regex = r'gimp_file_procedure_set_extensions\s*\([^,]+,\s*"([^"]+)"'
|
||||
label_regex = r'gimp_procedure_set_menu_label\s*\([^,]+,\s*_\("([^"]+)"\)\s*\)'
|
||||
elif source_file_ext == '.py':
|
||||
if "LoadProcedure" not in content:
|
||||
continue
|
||||
regex = fr'procedure\.{function_suffix}\s*\(\s*"([^"]+)"\s*\)'
|
||||
proc_regex = r'(LoadProcedure|VectorLoadProcedure)\.new'
|
||||
mime_regex = r'procedure\.set_mime_types\s*\(\s*"([^"]+)"\s*\)'
|
||||
ext_regex = r'procedure\.set_extensions\s*\(\s*"([^"]+)"\s*\)'
|
||||
label_regex = r'procedure\.set_menu_label\s*\(\s*_\("([^"]+)"\)\s*\)'
|
||||
else:
|
||||
continue
|
||||
for match in re.findall(regex, content, re.DOTALL):
|
||||
#(Take care of extensions separated by commas)
|
||||
for mime_extension in match.split(','):
|
||||
trimmed = mime_extension.strip()
|
||||
if trimmed:
|
||||
types_associations_list.add(trimmed)
|
||||
for proc_match in re.finditer(proc_regex, content):
|
||||
#proc_name = proc_match.group(1).strip()
|
||||
#key = (source_file, f"{proc_name}_{proc_match.start()}")
|
||||
key = (source_file, proc_match.start())
|
||||
if key not in types_associations_dict:
|
||||
types_associations_dict[key] = {"mime": set(), "extensions": set(), "label": set()}
|
||||
mime_match = re.search(mime_regex, content[proc_match.end():])
|
||||
if mime_match:
|
||||
#(Take care of mimes separated by commas)
|
||||
for mime in mime_match.group(1).split(','):
|
||||
trimmed_mime = mime.strip()
|
||||
if trimmed_mime:
|
||||
types_associations_dict[key]["mime"].add(trimmed_mime)
|
||||
ext_match = re.search(ext_regex, content[proc_match.end():])
|
||||
if ext_match:
|
||||
#(Take care of extensions separated by commas)
|
||||
for ext in ext_match.group(1).split(','):
|
||||
trimmed_ext = ext.strip()
|
||||
if trimmed_ext:
|
||||
types_associations_dict[key]["extensions"].add(trimmed_ext)
|
||||
label_match = re.search(label_regex, content[proc_match.end():])
|
||||
if label_match:
|
||||
types_associations_dict[key]["label"] = label_match.group(1).strip()
|
||||
|
||||
mode = sys.argv[1]
|
||||
if mode == "--mime":
|
||||
#Output string with the parsed MIME types
|
||||
print(";".join(sorted(types_associations_list)))
|
||||
all_mime = set()
|
||||
for values in types_associations_dict.values():
|
||||
all_mime.update(values["mime"])
|
||||
print(";".join(sorted(all_mime)))
|
||||
elif mode == "--association":
|
||||
#Create list with the parsed extensions
|
||||
output_file = sys.argv[2]
|
||||
all_ext = set()
|
||||
for values in types_associations_dict.values():
|
||||
all_ext.update(values["extensions"])
|
||||
try:
|
||||
with open(output_file, 'w', encoding='utf-8') as outf:
|
||||
outf.writelines(f"{assoc}\n" for assoc in sorted(types_associations_list))
|
||||
outf.writelines(f"{assoc}\n" for assoc in sorted(all_ext))
|
||||
except Exception as e:
|
||||
sys.stderr.write(f"(ERROR): When writing output file {output_file}: {e}\n")
|
||||
sys.exit(1)
|
||||
elif mode == "--pseudo-uti":
|
||||
output_file = sys.argv[2]
|
||||
try:
|
||||
with open(output_file, 'w', encoding='utf-8') as outf:
|
||||
for (source_file, proc_key), values in types_associations_dict.items():
|
||||
extensions = sorted(values["extensions"])
|
||||
mimes = sorted(values["mime"])
|
||||
if not extensions and not mimes:
|
||||
continue
|
||||
|
||||
outf.write("<dict>\n")
|
||||
if extensions:
|
||||
outf.write(" <key>CFBundleTypeExtensions</key>\n")
|
||||
outf.write(" <array>\n")
|
||||
for ext in extensions:
|
||||
outf.write(f" <string>{ext}</string>\n")
|
||||
outf.write(f" <string>{ext.upper()}</string>\n")
|
||||
outf.write(" </array>\n")
|
||||
|
||||
if mimes:
|
||||
outf.write(" <key>CFBundleTypeMIMETypes</key>\n")
|
||||
outf.write(" <array>\n")
|
||||
for mime in mimes:
|
||||
outf.write(f" <string>{mime}</string>\n")
|
||||
outf.write(" </array>\n")
|
||||
|
||||
outf.write(" <key>CFBundleTypeIconFile</key>\n")
|
||||
outf.write(" <string>fileicon</string>\n")
|
||||
|
||||
if "label" in values:
|
||||
outf.write(" <key>CFBundleTypeName</key>\n")
|
||||
outf.write(f" <string>{values['label']}</string>\n")
|
||||
elif extensions:
|
||||
outf.write(" <key>CFBundleTypeName</key>\n")
|
||||
outf.write(f" <string>{extensions[0].upper()} file</string>\n")
|
||||
|
||||
outf.write(" <key>CFBundleTypeRole</key>\n")
|
||||
outf.write(" <string>Viewer</string>\n")
|
||||
|
||||
outf.write(" <key>LSHandlerRank</key>\n")
|
||||
outf.write(" <string>Default</string>\n")
|
||||
outf.write("</dict>\n")
|
||||
except Exception as e:
|
||||
sys.stderr.write(f"(ERROR): When writing pseudo-UTI file {output_file}: {e}\n")
|
||||
sys.exit(1)
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@ if get_option('webkit-unmaintained')
|
|||
'name': 'help-browser',
|
||||
}
|
||||
endif
|
||||
|
||||
|
||||
if platform_windows and host_cpu_family == 'x86'
|
||||
complex_plugins_list += {
|
||||
'name': 'twain',
|
||||
|
|
@ -87,7 +87,7 @@ endforeach
|
|||
subdir('python')
|
||||
|
||||
foreach plugin : python_plugins
|
||||
if plugin.get('name').startswith('file-')
|
||||
if plugin.get('name').startswith('file-')
|
||||
all_plugins_sources += [ meson.current_source_dir() / 'python' / plugin.get('name') + '.py' ]
|
||||
endif
|
||||
endforeach
|
||||
|
|
@ -116,3 +116,17 @@ if get_option('windows-installer') or get_option('ms-store')
|
|||
build_by_default: true
|
||||
)
|
||||
endif
|
||||
|
||||
if get_option('dmg')
|
||||
custom_target('file_associations_mac',
|
||||
input : all_plugins_sources,
|
||||
output : 'file_associations_mac.list',
|
||||
command : [
|
||||
python,
|
||||
meson.current_source_dir() / 'generate_mime_ext.py',
|
||||
'--pseudo-uti',
|
||||
'@OUTPUT@',
|
||||
] + all_plugins_sources,
|
||||
build_by_default: true
|
||||
)
|
||||
endif
|
||||
|
|
|
|||
Loading…
Reference in a new issue