got rid of this confusing symlink stuff

xkb
sezanzeb 4 years ago committed by sezanzeb
parent b68b958160
commit a381613641

@ -1,8 +1,6 @@
# Folder Structure of Key Mapper
Stuff has to be placed in `/usr/share/X11/xkb` to my knowledge. In order to
be able to make backups of the configs, which would be expected in the
users home directory, this is symlinked to home where the actual files are.
Stuff has to be placed in `/usr/share/X11/xkb` to my knowledge.
Every user gets a path within that `/usr/...` directory which is very
unconventional, but it works. This way the presets of multiple users
@ -11,15 +9,12 @@ don't clash.
**Presets**
- `/usr/share/X11/xkb/symbols/key-mapper/<user>/<device>/<preset>`
- `/home/<user>/.config/key-mapper/<device>/<preset>`
This is how a single preset is stored. The path in /usr is a symlink, the
files are actually in home.
This is how a single preset is stored.
**Defaults**
- `/usr/share/X11/xkb/symbols/key-mapper/<user>/default`
- `/home/<user>/.config/key-mapper/default`
This is where key-mapper stores the defaults. They are generated from the
parsed output of `xmodmap` and used to keep the unmapped keys at their system

@ -37,35 +37,14 @@ import re
import shutil
import subprocess
from keymapper.paths import get_home_path, get_usr_path, KEYCODES_PATH, \
HOME_PATH, USERS_SYMBOLS, DEFAULT_SYMBOLS, X11_SYMBOLS
from keymapper.paths import get_usr_path, KEYCODES_PATH, \
USERS_SYMBOLS, DEFAULT_SYMBOLS, X11_SYMBOLS
from keymapper.logger import logger
from keymapper.data import get_data_path
from keymapper.linux import get_devices
from keymapper.mapping import custom_mapping, Mapping
def ensure_symlink():
"""Make sure the symlink exists.
It provides the configs in /home to X11 in /usr.
"""
if not os.path.exists(HOME_PATH):
os.makedirs(HOME_PATH, exist_ok=True)
if not os.path.exists(USERS_SYMBOLS):
# link from /usr/share/X11/xkb/symbols/key-mapper/user to
# /home/user/.config/key-mapper
logger.info('Linking "%s" to "%s"', USERS_SYMBOLS, HOME_PATH)
os.makedirs(os.path.dirname(USERS_SYMBOLS), exist_ok=True)
os.symlink(HOME_PATH, USERS_SYMBOLS, target_is_directory=True)
elif not os.path.islink(USERS_SYMBOLS):
logger.error('Expected %s to be a symlink', USERS_SYMBOLS)
else:
# expected
logger.debug('Symlink %s exists', USERS_SYMBOLS)
def create_preset(device, name=None):
"""Create an empty preset and return the potentially incremented name.
@ -76,26 +55,26 @@ def create_preset(device, name=None):
name = 'new preset'
# find a name that is not already taken
if os.path.exists(get_home_path(device, name)):
if os.path.exists(get_usr_path(device, name)):
i = 2
while os.path.exists(get_home_path(device, f'{name} {i}')):
while os.path.exists(get_usr_path(device, f'{name} {i}')):
i += 1
name = f'{name} {i}'
path = get_home_path(device, name)
path = get_usr_path(device, name)
if not os.path.exists(path):
logger.info('Creating new file %s', path)
os.makedirs(os.path.dirname(path), exist_ok=True)
os.mknod(path)
# give those files to the user
# TODO or should they stay root
user = os.getlogin()
for root, dirs, files in os.walk(HOME_PATH):
for root, dirs, files in os.walk(USERS_SYMBOLS):
shutil.chown(root, user, user)
for file in files:
shutil.chown(os.path.join(root, file), user, user)
ensure_symlink()
return name
@ -121,20 +100,18 @@ def create_setxkbmap_config(device, preset):
create_identity_mapping()
create_default_symbols()
home_device_path = get_home_path(device)
if not os.path.exists(home_device_path):
logger.info('Creating directory "%s"', home_device_path)
os.makedirs(home_device_path, exist_ok=True)
ensure_symlink()
device_path = get_usr_path(device)
if not os.path.exists(device_path):
logger.info('Creating directory "%s"', device_path)
os.makedirs(device_path, exist_ok=True)
home_preset_path = get_home_path(device, preset)
if not os.path.exists(home_preset_path):
logger.info('Creating config file "%s"', home_preset_path)
os.mknod(home_preset_path)
preset_path = get_usr_path(device, preset)
if not os.path.exists(preset_path):
logger.info('Creating config file "%s"', preset_path)
os.mknod(preset_path)
logger.info('Writing key mappings to %s', home_preset_path)
with open(home_preset_path, 'w') as f:
logger.info('Writing key mappings to %s', preset_path)
with open(preset_path, 'w') as f:
contents = generate_symbols(get_preset_name(device, preset))
if contents is not None:
f.write(contents)
@ -336,7 +313,7 @@ def parse_symbols_file(device, preset):
Existing mappings are overwritten if there are conflicts.
"""
path = get_home_path(device, preset)
path = get_usr_path(device, preset)
if not os.path.exists(path):
logger.debug(
@ -379,12 +356,11 @@ def create_default_symbols():
# TODO support an array of values in mapping and test it
defaults.change(None, int(keycode), characters.split()[0])
ensure_symlink()
contents = generate_symbols(DEFAULT_SYMBOLS_NAME, None, defaults)
if not os.path.exists(DEFAULT_SYMBOLS):
logger.info('Creating %s', DEFAULT_SYMBOLS)
os.makedirs(os.path.dirname(DEFAULT_SYMBOLS), exist_ok=True)
os.mknod(DEFAULT_SYMBOLS)
with open(DEFAULT_SYMBOLS, 'w') as f:

@ -24,15 +24,11 @@
import os
# the path in home, is symlinked with USERS_SYMBOLS.
# getlogin gets the user who ran sudo
HOME_PATH = os.path.join('/home', os.getlogin(), '.config/key-mapper')
# the path that contains ALL symbols, not just ours
X11_SYMBOLS = '/usr/share/X11/xkb/symbols'
# should not contain spaces
# getlogin gets the user who ran sudo
USERS_SYMBOLS = os.path.join(
'/usr/share/X11/xkb/symbols/key-mapper',
os.getlogin().replace(' ', '_')
@ -43,24 +39,6 @@ USERS_SYMBOLS = os.path.join(
KEYCODES_PATH = '/usr/share/X11/xkb/keycodes/key-mapper'
def get_home_path(device=None, preset=None):
"""Get the path to the config file in /usr."""
if device is None:
return HOME_PATH
device = device.strip()
if preset is not None:
preset = preset.strip()
return os.path.join(HOME_PATH, device, preset).replace(' ', '_')
if device is not None:
return os.path.join(HOME_PATH, device.replace(' ', '_'))
DEFAULT_SYMBOLS = get_home_path('default')
def get_usr_path(device=None, preset=None):
"""Get the path to the config file in /usr.
@ -79,3 +57,6 @@ def get_usr_path(device=None, preset=None):
if device is not None:
return os.path.join(USERS_SYMBOLS, device.replace(' ', '_'))
DEFAULT_SYMBOLS = get_usr_path('default')

@ -26,7 +26,7 @@ import os
import time
import glob
from keymapper.paths import get_home_path, HOME_PATH
from keymapper.paths import get_usr_path, USERS_SYMBOLS
from keymapper.logger import logger
from keymapper.linux import get_devices
@ -38,7 +38,7 @@ def get_presets(device):
----------
device : string
"""
device_folder = get_home_path(device)
device_folder = get_usr_path(device)
if not os.path.exists(device_folder):
os.makedirs(device_folder)
presets = [
@ -78,12 +78,12 @@ def find_newest_preset(device=None):
# sort the oldest files to the front in order to use pop to get the newest
if device is None:
paths = sorted(
glob.glob(os.path.join(HOME_PATH, '*/*')),
glob.glob(os.path.join(USERS_SYMBOLS, '*/*')),
key=os.path.getmtime
)
else:
paths = sorted(
glob.glob(os.path.join(get_home_path(device), '*')),
glob.glob(os.path.join(get_usr_path(device), '*')),
key=os.path.getmtime
)
@ -121,7 +121,7 @@ def find_newest_preset(device=None):
def delete_preset(device, preset):
"""Delete a preset from the file system."""
preset_path = get_home_path(device, preset)
preset_path = get_usr_path(device, preset)
if not os.path.exists(preset_path):
logger.debug('Cannot remove non existing path "%s"', preset_path)
return
@ -129,7 +129,7 @@ def delete_preset(device, preset):
logger.info('Removing "%s"', preset_path)
os.remove(preset_path)
device_path = get_home_path(device)
device_path = get_usr_path(device)
if os.path.exists(device_path) and len(os.listdir(device_path)) == 0:
logger.debug('Removing empty dir "%s"', device_path)
os.rmdir(device_path)
@ -139,16 +139,16 @@ def rename_preset(device, old_preset_name, new_preset_name):
"""Rename a preset while avoiding name conflicts."""
new_preset_name = new_preset_name.strip()
# find a name that is not already taken
if os.path.exists(get_home_path(device, new_preset_name)):
if os.path.exists(get_usr_path(device, new_preset_name)):
i = 2
while os.path.exists(get_home_path(device, f'{new_preset_name} {i}')):
while os.path.exists(get_usr_path(device, f'{new_preset_name} {i}')):
i += 1
new_preset_name = f'{new_preset_name} {i}'
logger.info('Moving "%s" to "%s"', old_preset_name, new_preset_name)
os.rename(
get_home_path(device, old_preset_name),
get_home_path(device, new_preset_name)
get_usr_path(device, old_preset_name),
get_usr_path(device, new_preset_name)
)
# set the modification date to now
now = time.time()
os.utime(get_home_path(device, new_preset_name), (now, now))
os.utime(get_usr_path(device, new_preset_name), (now, now))

@ -30,8 +30,7 @@ import unittest
from keymapper import paths
paths.X11_SYMBOLS = '/tmp/key-mapper-test/X11/symbols'
paths.USERS_SYMBOLS = '/tmp/key-mapper-test/X11/symbols/key-mapper/user'
paths.DEFAULT_SYMBOLS = '/tmp/key-mapper-test/user/.config/default'
paths.HOME_PATH = '/tmp/key-mapper-test/user/.config'
paths.DEFAULT_SYMBOLS = '/tmp/key-mapper-test/X11/symbols/key-mapper/user/default'
paths.KEYCODES_PATH = '/tmp/key-mapper-test/X11/keycodes/key-mapper'
from keymapper import linux

@ -26,8 +26,7 @@ import shutil
from keymapper.X import custom_mapping, generate_symbols, \
create_identity_mapping, create_setxkbmap_config, \
get_preset_name, create_default_symbols
from keymapper.paths import get_home_path, get_usr_path, KEYCODES_PATH, \
HOME_PATH, USERS_SYMBOLS
from keymapper.paths import get_usr_path, KEYCODES_PATH, USERS_SYMBOLS
from test import tmp
@ -44,12 +43,6 @@ class TestConfig(unittest.TestCase):
def test_create_setxkbmap_config(self):
create_setxkbmap_config('device a', 'preset b')
self.assertTrue(os.path.exists(os.path.join(
HOME_PATH,
'device_a',
'preset_b'
)))
self.assertTrue(os.path.exists(os.path.join(
USERS_SYMBOLS,
'device_a',
@ -58,7 +51,7 @@ class TestConfig(unittest.TestCase):
self.assertTrue(os.path.exists(KEYCODES_PATH))
with open(get_home_path('device_a', 'preset_b'), 'r') as f:
with open(get_usr_path('device_a', 'preset_b'), 'r') as f:
content = f.read()
self.assertIn('key <10> { [ a ] };', content)
self.assertIn('key <11> { [ KP_1 ] };', content)
@ -76,11 +69,9 @@ class TestConfig(unittest.TestCase):
create_identity_mapping()
create_default_symbols()
self.assertTrue(os.path.exists(get_home_path('default')))
self.assertTrue(os.path.exists(get_usr_path('default')))
self.assertTrue(os.path.islink(get_usr_path()))
with open(get_home_path('default'), 'r') as f:
with open(get_usr_path('default'), 'r') as f:
content = f.read()
self.assertNotIn('include', content)
# this is pretty much the same on every keyboard

@ -33,7 +33,7 @@ gi.require_version('Gtk', '3.0')
from gi.repository import Gtk
from keymapper.mapping import custom_mapping
from keymapper.paths import USERS_SYMBOLS, HOME_PATH, KEYCODES_PATH
from keymapper.paths import USERS_SYMBOLS, KEYCODES_PATH
from test import tmp
@ -189,7 +189,6 @@ class Integration(unittest.TestCase):
self.window.on_save_preset_clicked(None)
self.assertEqual(self.window.selected_preset, 'asdf')
self.assertTrue(os.path.exists(f'{USERS_SYMBOLS}/device_1/asdf'))
self.assertTrue(os.path.exists(f'{HOME_PATH}/device_1/asdf'))
self.assertEqual(custom_mapping.get(14), 'b')
def test_select_device_and_preset(self):
@ -236,7 +235,6 @@ class Integration(unittest.TestCase):
gtk_iteration()
self.assertEqual(self.window.selected_preset, 'abc 123')
self.assertTrue(os.path.exists(f'{USERS_SYMBOLS}/device_1/abc_123'))
self.assertListEqual(
sorted(os.listdir(USERS_SYMBOLS)),
['default', 'device_1']

@ -26,7 +26,7 @@ import time
from keymapper.presets import find_newest_preset, rename_preset
from keymapper.X import create_preset
from keymapper.paths import USERS_SYMBOLS, HOME_PATH
from keymapper.paths import USERS_SYMBOLS
from test import tmp
@ -39,23 +39,18 @@ class TestCreatePreset(unittest.TestCase):
def test_create_preset_1(self):
create_preset('device 1')
self.assertTrue(os.path.exists(f'{USERS_SYMBOLS}/device_1/new_preset'))
self.assertTrue(os.path.exists(f'{HOME_PATH}/device_1/new_preset'))
def test_create_preset_2(self):
create_preset('device 1')
create_preset('device 1')
self.assertTrue(os.path.exists(f'{USERS_SYMBOLS}/device_1/new_preset'))
self.assertTrue(os.path.exists(f'{HOME_PATH}/device_1/new_preset'))
self.assertTrue(os.path.exists(f'{USERS_SYMBOLS}/device_1/new_preset_2'))
self.assertTrue(os.path.exists(f'{HOME_PATH}/device_1/new_preset_2'))
def test_create_preset_3(self):
create_preset('device 1', 'pre set')
create_preset('device 1', 'pre set')
self.assertTrue(os.path.exists(f'{USERS_SYMBOLS}/device_1/pre_set'))
self.assertTrue(os.path.exists(f'{HOME_PATH}/device_1/pre_set'))
self.assertTrue(os.path.exists(f'{USERS_SYMBOLS}/device_1/pre_set_2'))
self.assertTrue(os.path.exists(f'{HOME_PATH}/device_1/pre_set_2'))
class TestRenamePreset(unittest.TestCase):
@ -63,9 +58,9 @@ class TestRenamePreset(unittest.TestCase):
create_preset('device 1', 'preset 1')
create_preset('device 1', 'foobar')
rename_preset('device 1', 'preset 1', 'foobar')
self.assertFalse(os.path.exists(f'{HOME_PATH}/device_1/preset_1'))
self.assertTrue(os.path.exists(f'{HOME_PATH}/device_1/foobar'))
self.assertTrue(os.path.exists(f'{HOME_PATH}/device_1/foobar_2'))
self.assertFalse(os.path.exists(f'{USERS_SYMBOLS}/device_1/preset_1'))
self.assertTrue(os.path.exists(f'{USERS_SYMBOLS}/device_1/foobar'))
self.assertTrue(os.path.exists(f'{USERS_SYMBOLS}/device_1/foobar_2'))
class TestFindPresets(unittest.TestCase):
@ -81,16 +76,13 @@ class TestFindPresets(unittest.TestCase):
def test_find_newest_preset_2(self):
os.makedirs(f'{USERS_SYMBOLS}/device_1')
os.makedirs(f'{HOME_PATH}/device_1')
time.sleep(0.01)
os.makedirs(f'{USERS_SYMBOLS}/device_2')
os.makedirs(f'{HOME_PATH}/device_2')
# takes the first one that the test-fake returns
self.assertEqual(find_newest_preset(), ('device 1', None))
def test_find_newest_preset_3(self):
os.makedirs(f'{USERS_SYMBOLS}/device_1')
os.makedirs(f'{HOME_PATH}/device_1')
self.assertEqual(find_newest_preset(), ('device 1', None))
def test_find_newest_preset_4(self):

@ -22,7 +22,7 @@
import unittest
from keymapper.linux import get_devices
from keymapper.paths import USERS_SYMBOLS, X11_SYMBOLS, HOME_PATH, \
from keymapper.paths import USERS_SYMBOLS, X11_SYMBOLS, \
DEFAULT_SYMBOLS
@ -33,9 +33,7 @@ class TestTest(unittest.TestCase):
def test_paths(self):
# stuff in /usr
self.assertTrue(USERS_SYMBOLS.startswith(X11_SYMBOLS))
# stuff in /home
self.assertTrue(DEFAULT_SYMBOLS.startswith(HOME_PATH))
self.assertTrue(DEFAULT_SYMBOLS.startswith(X11_SYMBOLS))
if __name__ == "__main__":

Loading…
Cancel
Save