Skip to content

hs.configdir resolution change in 0.9.79 breaks module loading for symlinked configsΒ #2478

@luckman212

Description

@luckman212

Thanks @asmagill, @cmsj, @latenitefilms β€” and to everyone else who contributed to this new release! πŸš€

I've been keeping my configs in sync between multiple Macs by symlinking init.lua (and other modules) into ~/.hammerspoon from a central config dir (~/Sync/Settings/Hammerpoon) using Resilio Sync.

My config failed to load when upgrading from 0.9.78. In the console, the following errors were logged:

...app/Contents/Resources/extensions/hs/_coresetup/init.lua:651: module 'keybinds' not found:
	no field package.preload['keybinds']
	no file '/Users/luke/Sync/Settings/Hammerspoon/keybinds.lua'
	no file '/Users/luke/Sync/Settings/Hammerspoon/keybinds/init.lua'
	no file '/Users/luke/Sync/Settings/Hammerspoon/Spoons/keybinds.spoon/init.lua'
        < ...snip... >
stack traceback:
	[C]: in function 'rawrequire'
	...app/Contents/Resources/extensions/hs/_coresetup/init.lua:651: in function 'require'
	(...tail calls...)
	[C]: in function 'xpcall'
	...app/Contents/Resources/extensions/hs/_coresetup/init.lua:514: in function <...app/Contents/Resources/extensions/hs/_coresetup/init.lua:494>

I eventually figured out that this was due to a change in the way hs.configdir is resolved. Previously, it seems like it would resolve to ~/.hammerspoon but now, if init.lua is itself a symlink, then hs.configdir is set to the parent directory of the absolute path of the real file. This is probably fine for 99.9% of usersβ€” but in my case, it broke my configuration.

I have the following symlinks:

~/.hammerspoon/init.lua       β†’  ~/Sync/Settings/Hammerspoon/init-XXX-YYY.lua
~/.hammerspoon/keybinds.lua   β†’  ~/Sync/Settings/Hammerspoon/keybinds-XXX-YYY.lua

(where XXX=hostname and YYY=machine serial number)

The reason I do this is so I can share chunks of configuration in init.lua between multiple Macs, but have the keybinds/module settings be specific to the machine that's loading them. I symlink a custom file for each machine but they are all named e.g. "keybinds.lua".

I "fixed" it by adding a function to my init.lua:

function require_safe(m)
  local rs_abspath = hs.fs.pathToAbsolute(os.getenv('HOME') .. '/.hammerspoon/' .. m .. '.lua')
  if not rs_abspath then return end
  local rs_basename = string.gsub(rs_abspath, "(.*/)(.*)", "%2")
  local rs_modname = rs_basename:sub(1, -5)
  return require(rs_modname)
end

-- instead of require('keybinds')
require_safe('keybinds')

This has gotten things working again for me. But I'm guessing there's a cleaner way to handle this...?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions