diff --git a/linux/keyman-config/.editorconfig b/linux/keyman-config/.editorconfig
index 020438e0c6..6707d70e59 100644
--- a/linux/keyman-config/.editorconfig
+++ b/linux/keyman-config/.editorconfig
@@ -2,3 +2,6 @@
[*]
indent_style = space
indent_size = 4
+
+[*.sharedmimeinfo]
+indent_style = tab
\ No newline at end of file
diff --git a/linux/keyman-config/debian/keyman.sharedmimeinfo b/linux/keyman-config/debian/keyman.sharedmimeinfo
index 273dcf9d8d..569866b403 100644
--- a/linux/keyman-config/debian/keyman.sharedmimeinfo
+++ b/linux/keyman-config/debian/keyman.sharedmimeinfo
@@ -6,4 +6,7 @@
+
+ Keyman keyboard installation link
+
diff --git a/linux/keyman-config/debian/km-config.desktop b/linux/keyman-config/debian/km-config.desktop
index e37c297054..83bf1a8b99 100644
--- a/linux/keyman-config/debian/km-config.desktop
+++ b/linux/keyman-config/debian/km-config.desktop
@@ -3,7 +3,7 @@ Name=Keyman Keyboards
Name[en_GB]=Keyman Keyboards
Comment=Configure Keyman keyboards
Comment[en_GB]=Configure Keyman keyboards
-Exec=km-config -i %f
+Exec=km-config -i %u
Icon=km-config
Terminal=false
Type=Application
@@ -11,4 +11,4 @@ StartupNotify=true
Categories=Settings;
Keywords=keyman;keyboard;input;
X-Desktop-File-Install-Version=0.21
-MimeType=application/x-kmp;x-scheme-handler/x-kmp
+MimeType=application/x-kmp;x-scheme-handler/x-kmp;application/keyman;x-scheme-handler/keyman
diff --git a/linux/keyman-config/keyman_config/handle_install.py b/linux/keyman-config/keyman_config/handle_install.py
new file mode 100644
index 0000000000..af341fda33
--- /dev/null
+++ b/linux/keyman-config/keyman_config/handle_install.py
@@ -0,0 +1,63 @@
+import logging
+import os
+
+from urllib.parse import parse_qs, urlparse
+from keyman_config import KeymanComUrl, __tier__
+from keyman_config.install_window import InstallKmpWindow
+from keyman_config.get_kmp import get_download_folder, download_kmp_file
+
+
+def download_and_install_package(url):
+ """
+ Handle the download and installation of the given package. This can either be a .kmp
+ file that got downloaded previously, or a keyman:// URL which will be downloaded and
+ installed.
+
+ Args:
+ url: a .kmp file, a keyman:// URL, or a file:// URL pointing to a .kmp file,
+ possibly with a bcp47= specified
+ """
+ parsedUrl = urlparse(url)
+ bcp47 = _extract_bcp47(parsedUrl.query)
+
+ if parsedUrl.scheme == 'keyman':
+ logging.info("downloading " + url)
+ if not url.startswith('keyman://download/keyboard/'):
+ logging.error("Don't know what to do with URL " + url)
+ return
+
+ packageId = parsedUrl.path[len('/keyboard/'):]
+ if not packageId:
+ logging.error("Missing package id")
+ return
+
+ downloadFile = os.path.join(get_download_folder(), packageId)
+ downloadUrl = KeymanComUrl + '/go/package/download/' + packageId + '?platform=linux&tier=' + __tier__
+ packageFile = download_kmp_file(downloadUrl, downloadFile)
+ elif parsedUrl.scheme == '' or parsedUrl.scheme == 'file':
+ packageFile = parsedUrl.path
+ else:
+ logging.error("Invalid URL: " + url)
+ return
+
+ if not _install_package(packageFile, bcp47):
+ logging.error("Can't find file " + url)
+
+
+def _extract_bcp47(query):
+ if query:
+ queryStrings = parse_qs(query)
+ values = queryStrings['bcp47']
+ if len(values) > 0:
+ return values[0]
+ return ''
+
+
+def _install_package(packageFile, bcp47):
+ if not os.path.isfile(packageFile):
+ return False
+
+ w = InstallKmpWindow(packageFile, language=bcp47)
+ w.run()
+ w.destroy()
+ return True
diff --git a/linux/keyman-config/km-config b/linux/keyman-config/km-config
index d362340732..a8cd4c2b6f 100755
--- a/linux/keyman-config/km-config
+++ b/linux/keyman-config/km-config
@@ -2,9 +2,9 @@
import argparse
import logging
-import os
from keyman_config import __version__
+from keyman_config.handle_install import download_and_install_package
if __name__ == '__main__':
@@ -23,13 +23,7 @@ if __name__ == '__main__':
logging.basicConfig(format='%(levelname)s:%(message)s')
if args.install:
- if os.path.isfile(args.install):
- from keyman_config.install_window import InstallKmpWindow
- w = InstallKmpWindow(args.install)
- w.run()
- w.destroy()
- else:
- logging.error("Can't find file " + args.install)
+ download_and_install_package(args.install)
else:
from keyman_config.view_installed import ViewInstalledWindow
w = ViewInstalledWindow()
diff --git a/linux/keyman-config/tests/test_handle_install.py b/linux/keyman-config/tests/test_handle_install.py
new file mode 100644
index 0000000000..a2745e5623
--- /dev/null
+++ b/linux/keyman-config/tests/test_handle_install.py
@@ -0,0 +1,106 @@
+#!/usr/bin/python3
+import unittest
+from unittest.mock import patch
+
+from keyman_config import KeymanComUrl
+from keyman_config.handle_install import download_and_install_package
+
+
+class HandleInstallTests(unittest.TestCase):
+
+ @patch('keyman_config.handle_install._install_package')
+ def test_downloadAndInstallPackage_file(self, installPackageMethod):
+ # Execute
+ download_and_install_package('/tmp/keyboard/sil_euro_latin.kmp')
+
+ # Verify
+ installPackageMethod.assert_called_with('/tmp/keyboard/sil_euro_latin.kmp', '')
+
+ @patch('keyman_config.handle_install._install_package')
+ def test_downloadAndInstallPackage_fileUrl(self, installPackageMethod):
+ # Execute
+ download_and_install_package('file:///tmp/keyboard/sil_euro_latin.kmp')
+
+ # Verify
+ installPackageMethod.assert_called_with('/tmp/keyboard/sil_euro_latin.kmp', '')
+
+ @patch('keyman_config.handle_install._install_package')
+ def test_downloadAndInstallPackage_fileUrlWithBcp47(self, installPackageMethod):
+ # Execute
+ download_and_install_package('file:///tmp/keyboard/sil_euro_latin.kmp?bcp47=dyo')
+
+ # Verify
+ installPackageMethod.assert_called_with('/tmp/keyboard/sil_euro_latin.kmp', 'dyo')
+
+ @patch('keyman_config.handle_install._install_package')
+ def test_downloadAndInstallPackage_fileUrlWithBcp47AndVersion(self, installPackageMethod):
+ # Execute
+ download_and_install_package('file:///tmp/keyboard/sil_euro_latin.kmp?bcp47=dyo&version=1')
+
+ # Verify
+ installPackageMethod.assert_called_with('/tmp/keyboard/sil_euro_latin.kmp', 'dyo')
+
+ @patch('keyman_config.handle_install._install_package')
+ def test_downloadAndInstallPackage_InvalidUrl(self, installPackageMethod):
+ # Execute
+ download_and_install_package('http://localhost/keyboard/sil_euro_latin.kmp')
+
+ # Verify
+ installPackageMethod.assert_not_called()
+
+ @patch('keyman_config.handle_install._install_package')
+ @patch('keyman_config.get_kmp.download_kmp_file')
+ def test_downloadAndInstallPackage_invalidUrl(self, downloadKmpFileMethod,
+ installPackageMethod):
+ for url in ['foo://download/keyboard/sil_euro_latin', 'keyman://keyboard/sil_euro_latin',
+ 'keyman://download/sil_euro_latin', 'keyman://download/keyboard/']:
+ with self.subTest(url=url):
+ # Execute
+ download_and_install_package(url)
+
+ # Verify
+ downloadKmpFileMethod.assert_not_called()
+ installPackageMethod.assert_not_called()
+
+ @patch('keyman_config.handle_install._install_package')
+ @patch('keyman_config.get_kmp.keyman_cache_dir')
+ @patch('keyman_config.handle_install.download_kmp_file')
+ def test_downloadAndInstallPackage_keymanUrl(self, downloadKmpFileMethod,
+ keymanCacheDirMethod, installPackageMethod):
+ # Setup
+ mockPackagePath = '/tmp/sil_euro_latin'
+ keymanCacheDirMethod.return_value = '/tmp'
+ downloadKmpFileMethod.return_value = mockPackagePath
+
+ # Execute
+ download_and_install_package('keyman://download/keyboard/sil_euro_latin')
+
+ # Verify
+ downloadKmpFileMethod.assert_called_with(
+ KeymanComUrl + '/go/package/download/sil_euro_latin?platform=linux&tier=alpha',
+ mockPackagePath)
+ installPackageMethod.assert_called_with(mockPackagePath, '')
+
+ @patch('keyman_config.handle_install._install_package')
+ @patch('keyman_config.get_kmp.keyman_cache_dir')
+ @patch('keyman_config.handle_install.download_kmp_file')
+ def test_downloadAndInstallPackage_keymanUrlWithBcp47(self, downloadKmpFileMethod,
+ keymanCacheDirMethod,
+ installPackageMethod):
+ # Setup
+ mockPackagePath = '/tmp/sil_euro_latin'
+ keymanCacheDirMethod.return_value = '/tmp'
+ downloadKmpFileMethod.return_value = mockPackagePath
+
+ # Execute
+ download_and_install_package('keyman://download/keyboard/sil_euro_latin?bcp47=de')
+
+ # Verify
+ downloadKmpFileMethod.assert_called_with(
+ KeymanComUrl + '/go/package/download/sil_euro_latin?platform=linux&tier=alpha',
+ mockPackagePath)
+ installPackageMethod.assert_called_with(mockPackagePath, 'de')
+
+
+if __name__ == '__main__':
+ unittest.main()