Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Mac compability #8

Open
wants to merge 37 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 29 commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
2aa53f6
It starts on macos, need to work on the desktop entries
peauc Jan 24, 2019
87682be
added app bundle
lokoum Jan 29, 2019
d6ebc8c
The solution is now launched via iQuail on OSX
lokoum Mar 25, 2019
d35f3db
OSX - Started to work on a proper xml way of writing plist files
peauc Mar 26, 2019
ebcbfcd
Merge branch 'master' into mac_compability
lokoum Mar 26, 2019
1af7eb6
Fixed some variables names
lokoum Mar 26, 2019
8d491ee
Merge branch 'mac_compability' of https://github.com/QuailTeam/iQuail…
lokoum Mar 26, 2019
67f9841
Fixed code from the feedback review
lokoum Mar 26, 2019
b563fd6
Removed a syntax error
peauc Mar 26, 2019
206afa3
Fix bundle path
lokoum Mar 27, 2019
95c6e94
Merge branch 'mac_compability' of https://github.com/QuailTeam/iQuail…
lokoum Mar 27, 2019
6154eae
Adding a new feature to parse and write xml files for our OSX install.
peauc Apr 22, 2019
a19b6c8
Added new tests for our xml feature
peauc Apr 22, 2019
310fe69
Hey we have icons on osx now -> Extra s in resource folder
peauc Apr 23, 2019
7706633
Forgot to commit the file (Couldn't ammend don't know why)
peauc Apr 23, 2019
d4c9dae
fixed wrong syntax on class declaration
peauc Apr 23, 2019
2050428
Merging master from mac_compatibility
peauc Oct 23, 2019
fee4133
Auto stash before merge of "mac_compability" and "origin/master"
peauc Oct 23, 2019
7d06807
Missing an S to the application's folder
peauc Oct 24, 2019
fae2ecc
Fixing some variable name and removing old comments
peauc Oct 24, 2019
0ce224c
Added key/value adding in plcreator
peauc Oct 24, 2019
aea3b82
We are now creating valid .plist files
peauc Oct 24, 2019
8532d48
Skipping IOS test on different platforms
peauc Oct 24, 2019
aed062d
removed an old file.
peauc Oct 24, 2019
850ec11
Refactored the plist_creator.py file
peauc Oct 24, 2019
96f2edf
Changed the error message when tkinter is not found
peauc Oct 24, 2019
b3c39e3
Added a todo
peauc Oct 24, 2019
23e6dfe
Merge branch 'master' into mac_compability
lokoum Dec 9, 2019
73f5bd9
Cleaned the installer OSX file and added local installation
peauc Dec 11, 2019
8c9dd30
Cleaned the installer OSX file and added local installation
peauc Dec 11, 2019
3239bcd
Refactoring
peauc Dec 11, 2019
252a4b0
Made the ios import exclusive to ios
peauc Dec 11, 2019
f9a0ebc
Added support for user designed icon on the OSx installation
peauc Dec 11, 2019
fc6cae9
Merge branch 'mac_compability' of https://github.com/QuailTeam/iQuail…
lokoum Dec 12, 2019
3332f31
added github full solution handling
peauc Dec 12, 2019
83bd11d
fix bugs about PATH for local binaries, added eexample for PKG with GUI
lokoum Dec 12, 2019
977c7ce
ready for merging with master
lokoum Dec 12, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -109,3 +109,6 @@ ENV/

# mypy
.mypy_cache/

#Don't add mac's dsstore
*.DS_Store*
1 change: 1 addition & 0 deletions examples/MacCalc/.integrity.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"maccalc": "bdee4331072ce68954b7aa6d090165bc638474bf9515114a72d5baf86fa415af"}
2 changes: 2 additions & 0 deletions examples/MacCalc/maccalc
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
#!/usr/bin/env bash
open -a calculator && cat
13 changes: 13 additions & 0 deletions examples/test_local.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,19 @@
iquail.builder.CmdIntegrity(solution_path)
)
)
if iquail.helper.OS_OSX:
solution_path = ['Allum1']
iquail.run(
iquail.SolutionLocal(['Allum1']),
iquail.Installer(
name='Allum1',
publisher='alies',
icon='icon.jpeg',
binary='allum1',
console=True,
),
iquail.builder.Builder(iquail.builder.CmdIntegrity(solution_path))
)
if iquail.helper.OS_WINDOWS:
solution_path = ['OpenHardwareMonitor']
iquail.run(
Expand Down
17 changes: 17 additions & 0 deletions examples/test_osx.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#!/usr/bin/python3

import iquail

if iquail.helper.OS_OSX:
solution_path = ['MacCalc']
iquail.run(
iquail.SolutionLocal(['MacCalc']),
iquail.Installer(
name='MacCalc',
publisher='test',
icon='icon.jpeg',
binary='maccalc',
console=True,
),
iquail.builder.Builder(iquail.builder.CmdIntegrity(solution_path))
)
7 changes: 6 additions & 1 deletion iquail/controller/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
import sys

from .controller_base import ControllerBase
from .controller_tkinter import ControllerTkinter
try:
from .controller_tkinter import ControllerTkinter
except ImportError as e:
print(f"Tkinter not found....", file=sys.stderr)
from .controller_console import ControllerConsole
2 changes: 1 addition & 1 deletion iquail/controller/controller_console.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ def start_uninstall(self):
self.manager.uninstall()
print("[*] %s successfully removed!" % self.manager.get_name())
self.press_to_exit()
except:
except Exception as e:
print(
"[*] Unknown error while uninstalling %s" % self.manager.get_name())
self.press_to_exit()
Expand Down
1 change: 1 addition & 0 deletions iquail/helper/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@
from .integrity_verifier import IntegrityVerifier, checksum_file
from .configuration import Configuration, ConfVar
from .linux_polkit_file import polkit_install, polkit_check
from .osx import BundleTemplate, PlistCreator
peauc marked this conversation as resolved.
Show resolved Hide resolved
1 change: 1 addition & 0 deletions iquail/helper/misc.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

OS_LINUX = platform.system() == 'Linux'
OS_WINDOWS = platform.system() == 'Windows'
OS_OSX = platform.system() == 'Darwin'


def cache_result(func):
Expand Down
2 changes: 2 additions & 0 deletions iquail/helper/osx/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
from .bundle_template import BundleTemplate
from .plist_creator import PlistCreator
16 changes: 16 additions & 0 deletions iquail/helper/osx/bundle_template.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import os


class BundleTemplate:
def __init__(self, bundle_name: str, base_dir='/Applications'):
self.full_path = os.path.join(base_dir, bundle_name + ".app")
self.names = [
self.full_path,
os.path.join(self.full_path, 'Contents'),
os.path.join(self.full_path, 'Contents/MacOS'),
os.path.join(self.full_path, 'Contents/Resources')
]

def make(self):
for path in self.names:
os.mkdir(path)
78 changes: 78 additions & 0 deletions iquail/helper/osx/plist_creator.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import os
import xml.etree.ElementTree as ET


class PlistCreator:
def __init__(self, bundle_name: str, application_path: str, plist_dict=None):
# The argument plist_dict can't be mutable
if not plist_dict:
plist_dict = {}
self.__filename = os.path.join(application_path, bundle_name + ".app/Contents/Info.plist")
self.__data = ""
self.__plist_dict = {
"CFBundleGetInfoString": bundle_name,
"CFBundleExecutable": 'launcher',
"CFBundleIdentifier": bundle_name,
"CFBundleName": bundle_name
}
self.__plist_header = """
<?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">
"""
self.__plist_dict.update(plist_dict)

@property
def plist_dict(self):
return self.__plist_dict

def __make_key_with_text(self, key: str, value: str):
item = ET.Element(key)
item.text = value
return item

def __indent_tree(self, elem, level=0):
i = "\n" + level * " "
if len(elem):
if not elem.text or not elem.text.strip():
elem.text = i + " "
if not elem.tail or not elem.tail.strip():
elem.tail = i
for elem in elem:
self.__indent_tree(elem, level + 1)
if not elem.tail or not elem.tail.strip():
elem.tail = i
else:
if level and (not elem.tail or not elem.tail.strip()):
elem.tail = i

def __add_icon(self, root: ET.Element, icon_name: str):
root.append(self.__make_key_with_text('key', 'CFBundleIconFile'))
root.append(self.__make_key_with_text('string', icon_name))

def __create_tree(self) -> ET.Element:
root = ET.Element('plist', {'version':'1.0'})
return root

def build_tree_and_write_file(self):
tree = self.__create_tree()

self.__data += self.__plist_header
self.__add_dict_content_to_tree(tree)
self.__indent_tree(tree)
self.__write_to_file(tree)

def __add_dict_content_to_tree(self, root: ET.Element):
elem = ET.Element('dict')
for key, value in self.plist_dict.items():
elem.append(self.__make_key_with_text('key', key))
elem.append(self.__make_key_with_text('string', value))
root.append(elem)

def __write_to_file(self, tree):
tree_data = ET.tostring(tree, encoding='unicode')
with open(self.__filename, 'w+') as f:
total_data = self.__data + tree_data
f.write(total_data)



4 changes: 3 additions & 1 deletion iquail/installer/installer.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,6 @@
from .installer_windows import InstallerWindows
Installer = InstallerWindows
else:
raise NotImplementedError
from .installer_osx import InstallerOsx
Installer = InstallerOsx

53 changes: 53 additions & 0 deletions iquail/installer/installer_osx.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
from .installer_base import InstallerBase
import os
import stat
import shutil
import pathlib
from ..helper import BundleTemplate, PlistCreator

class InstallerOsx(InstallerBase):

def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self._bundle_install_path = os.path.join(self._get_application_folder_path(), self.name + '.app')

""" TODO: Add the icon to the bundle"""
def _register(self):
bundle = BundleTemplate(self.name, base_dir=self._get_application_folder_path())
bundle.make()
plist = PlistCreator(self.name, self._get_application_folder_path(), {})
plist.build_tree_and_write_file()
self._build_launcher()
#self.add_to_path(self.binary, self._binary_name)

def _unregister(self):
self.__remove_from_path(self.binary)

def _registered(self):
if not os.path.exists(self.build_folder_path(self.binary)):
return False
return True

def __add_to_path(self, binary, name):
os.symlink(binary, self.build_folder_path(name))

def __remove_from_path(self, name):
peauc marked this conversation as resolved.
Show resolved Hide resolved
shutil.rmtree(self._bundle_install_path)

def _get_application_folder_path(self):
if self.install_systemwide:
return os.path.join(os.sep, 'Applications')
return os.path.join(str(pathlib.Path.home()), 'Applications')

def build_folder_path(self, name):
final_folder = os.path.join(self._get_application_folder_path(), self._name + '.app', 'Contents', 'MacOS')
return os.path.join(final_folder, name)

def _build_launcher(self):
with open(os.path.join(self._bundle_install_path, 'Contents', 'MacOS', 'launcher'), 'w') as f:
shebang = '#!/usr/bin/env bash\n'
content = '/usr/bin/env python3 ~/.iquail/' + self.uid + '/iquail_launcher.py'
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

c'est toujours hardcodé

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Resolved dans le last commit

f.write(shebang)
f.write(content)
st = os.stat(os.path.join(self._bundle_install_path, 'Contents', 'MacOS', 'launcher'))
os.chmod(os.path.join(self._bundle_install_path, 'Contents', 'MacOS', 'launcher'), st.st_mode | stat.S_IEXEC)
20 changes: 20 additions & 0 deletions tests/base_test_osx_bundle.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import iquail.helper

if iquail.helper.OS_OSX:
import shutil
mouuff marked this conversation as resolved.
Show resolved Hide resolved

peauc marked this conversation as resolved.
Show resolved Hide resolved
from tests.base_test_case import BaseTestCase
from iquail.helper.osx.bundle_template import BundleTemplate
from iquail.helper.osx.plist_creator import PlistCreator


class BaseTestOsxBundle(BaseTestCase):
# The test folder will always be named test.app
def setUp(self):
super(BaseTestOsxBundle, self).setUp()
self._test_folder_path = self.tmp('test.app')
self.bt = BundleTemplate('test', self._tmpdir)
self.bt.make()

def tearDown(self):
shutil.rmtree(self.bt.full_path, ignore_errors=True)
22 changes: 22 additions & 0 deletions tests/test_bundle_osx.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import iquail.helper

if iquail.helper.OS_OSX:
import os

from iquail.helper.osx.plist_creator import PlistCreator
from tests.base_test_osx_bundle import BaseTestOsxBundle


class TestOsxBundle(BaseTestOsxBundle):
"""
In this test we make sure that the proper folder has the right name and that all the subfolders are created correctly
"""
def test_default_bundle_setup(self):
# Bundle template create a folder appended with .app
assert os.path.exists(self._test_folder_path)
assert os.path.exists(os.path.join(self._test_folder_path, 'Contents'))

def test_plist_creation(self):
plist_creator = PlistCreator('test', self._tmpdir)
plist_creator.build_tree_and_write_file()
assert os.path.exists(os.path.join(self._test_folder_path, 'Contents', 'info.plist'))