better config format

course, it does nothing right now
master
Jordan Orelli 2 years ago
parent 30d476768f
commit c6c489fc71

@ -1,7 +1,10 @@
if !has('nvim')
nnoremap <buffer> <C-]> :ALEGoToDefinition<CR>
endif
" f5 runs the current project
nmap <F5> :!clear<CR>:!cargo run -q<CR>
nmap <S-F5> :!clear<CR>:!cargo run<CR>
nnoremap <F5> :Cargo run<CR>
" ctrl-f5 lets you run the current program but prompts you for the cli args
nmap <C-F5> :!clear<CR>:!cargo run --
let g:rustfmt_autosave = 1
nmap <F6> :!clear<CR>:!cargo run<CR>
nmap <F7> :!clear<CR>:!cargo check<CR>
nmap <F8> :!clear<CR>:!cargo test<CR>

@ -1,34 +1,46 @@
# items in the [home] section are copied into the home directory with the same
# relative location as they appear in the dotfiles repo
[home]
files=
# sync vim plugin directories but not all of .vim
.vim/ftplugin
.vim/pack
# individual files to sync
.bash_profile
.bashrc
.screenrc
.tmux.conf
.vimrc
.config/htop/htoprc
.config/lazydocker/config.yml
# items in map.posix define a place where config files will be placed on posix
# systems relative to the user's home directory
[map.posix]
nvim/init.vim=.config/nvim/init.vim
scripts/winmode=bin/winmode
# items in the map.windows section defines a place where config files will be
# placed on windows, relative to the user's home directory
[map.windows]
.vimrc=AppData/Local/nvim/init.vim
Vundle.vim=AppData/Local/nvim/bundle/Vundle.vim
.vim/ftplugin=AppData/Local/nvim/ftplugin
packer.nvim=AppData/Local/nvim-data/site/pack/packer/start/packer.nvim
nvim/lua=AppData/Local/nvim/lua
cargo-config.toml=.cargo/config.toml
[cargo:gitui]
files:
# sync vim plugin directories but not all of .vim
.vim/ftplugin
.vim/pack
# individual files to sync
.bash_profile
.bashrc
.vimrc
cargo-config.toml > .cargo/config.toml
[home posix]
when: not host.is_windows
files:
.screenrc
.tmux.conf
.config/lazydocker/config.yml
.config/htop/htoprc
nvim/init.vim > .config/nvim/init.vim
[home wsl]
when: host.is_wsl
files:
scripts/winmode > bin/winmode
[link-files AppData]
when: host.is_windows
target_root: ~/AppData/Local
files:
nvim/lua
.vimrc > nvim/init.vim
Vundle.vim > nvim/bundle/Vundle.vim
.vim/ftplugin > nvim/ftplugin
packer.nvim > nvim-data/site/pack/packer/start/packer.nvim
# [cargo:gitui]

@ -3,6 +3,6 @@
installs preferences
"""
from prefs import Installer
from prefs.installer import Installer
installer = Installer()
installer.run()

@ -1,5 +0,0 @@
"""
prefs is a preferences manager
"""
from .installer import Installer

@ -1,33 +1,32 @@
class Home:
def __init__(self, label = None):
self.label = label
from . import host
from .linker import Linker
@classmethod
def from_name(cls, name):
"""
Builds a Home struct from a given name
"""
if name.startswith('home'):
label = name.removeprefix('home').strip()
return cls(label)
return None
class Home:
resource_name = 'home'
def parse_section(self, section):
mapping = {
'files': self.parse_files
}
for key in section:
if fn := mapping.get(key):
val = section[key]
fn(val)
else:
raise KeyError(f"Home has no such config key: {key}")
def __init__(self, label, section):
self.label = label or None
self.parse_files(section.get('files', ''))
def parse_files(self, text):
self.files = []
lines = [s for s in text.splitlines() if s]
print(f" parse_files: {lines}")
for line in lines:
parts = line.split(">", 2)
if len(parts) == 1:
pair = (parts[0].strip(), parts[0].strip())
else:
pair = (parts[0].strip(), parts[1].strip())
self.files.append(pair)
def __repr__(self):
if self.label:
return f'<Home: {self.label}>'
return '<Home>'
def run(self):
linker = Linker(host.dotfiles_root, host.home)
for pair in self.files:
source_path = host.dotfiles_root / pair[0]
target_path = host.home / pair[1]
linker.link(source_path, target_path)

@ -10,7 +10,7 @@ import sys
import pathlib
from functools import cached_property
class _Host:
class Host:
"""
hacking the python module system a little to make the module look like a
singleton object so that it can have properties
@ -54,5 +54,11 @@ class _Host:
here = pathlib.Path(os.path.realpath(__file__))
return here.parent.parent
@property
def home(self):
"""
the home directory
"""
return pathlib.Path.home()
sys.modules[__name__] = _Host()
sys.modules[__name__] = Host()

@ -26,105 +26,18 @@ class Installer:
parser.optionxform = str
parser.read_file(config_file)
return parser
self._config = parser
def run(self):
"""
runs the install process
"""
if self.options.x:
self.run_x()
return
if host.is_windows and not host.is_admin:
print("You are not admin: admin is required on Windows")
sys.exit(1)
config = self.config
for section_name in config.sections():
try:
T = self.parse_section_name(section_name)
except ValueError as e:
print(f"error reading section: {e}")
continue
section = T.from_section(section_name, **config[section_name])
print(f"Section: {section}")
section.run()
print("linking in home files")
home = self.options.config['home']
home_files = filter(None, home['files'].splitlines())
for fname in home_files:
print(f"\n{fname}")
path = pathlib.Path(fname)
self.map_file(path, path)
if host.is_linux:
self.map_section('map.posix')
self.map_section('map.windows')
if host.is_windows:
self.map_section('map.windows')
def run_x(self):
for section_name in self.config.sections():
print("sections:")
print(f" {section_name}")
if r := Resource.from_name(section_name):
print(f" {r}")
r.parse_section(self.config[section_name])
@cached_property
def targets(self):
"""
defines all of the places where preferences files will be installed
"""
if host.is_linux:
return [targets.Linux()]
if host.is_windows:
return [targets.Windows()]
return []
def map_file(self, source_path, target_path):
if not source_path.is_absolute():
source_path = host.dotfiles_root / source_path
print(f"source path: {source_path}")
print(f"source drive: {source_path.drive}")
if not source_path.exists():
print("skip: no such file\n")
return
for target in self.targets:
target.map_file(source_path, target_path)
@property
def config_path(self):
# pylint: disable=missing-function-docstring
return self.options.config
# @cached_property
# def config(self):
# """
# the contents of our configuration file
# """
# with open(self.config_path, 'r', encoding='utf-8') as config_fp:
# log.debug("loading config from path %s", self.config_path)
# return json.load(config_fp)
def map_section(self, section_name):
section = self.options.config[section_name]
for source_name in section:
target_name = section[source_name]
source_path = pathlib.Path(source_name)
target_path = pathlib.Path(target_name)
print(f"Map {source_path} to {target_path}")
self.map_file(source_path, target_path)
def parse_section_name(self, section_name):
if section_name == "home":
return sections.Home
raise ValueError(f"unprocessable section name: {section_name}")
resources = []
for name in self.config.sections():
section = self.config[name]
if self.when(section):
r = Resource.from_section(name, section)
resources.append(r)
for r in resources:
r.run()
def when(self, section):
if clause := section.get('when', None):
return eval(clause)
return True

@ -0,0 +1,56 @@
import pathlib
from . import host
class Linker:
"""
Linker links files from soome source to some target
"""
def __init__(self, source_root, target_root):
self.source_root = source_root
self.target_root = target_root
def link(self, source_path, target_path):
if not source_path.is_absolute():
source_path = self.source_root / source_path
if not target_path.is_absolute():
target_path = self.target_root / target_path
if not target_path.parent.exists():
print("creating missing parent directories for target")
parent_dir = target_path.parent
parent_dir.mkdir(parents=True)
print(f"{source_path} -> {target_path}")
class LinkFiles:
resource_name = 'link-files'
def __init__(self, label, section):
self.label = label
self.target_root = pathlib.Path(section['target_root']).expanduser()
self.source_root = host.dotfiles_root
self.parse_files(section.get('files', ''))
def parse_files(self, text):
self.files = []
lines = [s for s in text.splitlines() if s]
for line in lines:
parts = line.split(">", 2)
if len(parts) == 1:
pair = (parts[0].strip(), parts[0].strip())
else:
pair = (parts[0].strip(), parts[1].strip())
self.files.append(pair)
def __repr__(self):
if self.label:
return f'<LinkFiles: {self.label}>'
return '<LinkFiles>'
def run(self):
linker = Linker(host.dotfiles_root, self.target_root)
for pair in self.files:
source_path = pathlib.Path(pair[0])
target_path = pathlib.Path(pair[1])
linker.link(source_path, target_path)

@ -1,7 +1,8 @@
from .home import Home
from .linker import LinkFiles
class Resource:
resource_types = [Home]
resource_types = [Home, LinkFiles]
@classmethod
def from_name(cls, name):
@ -9,9 +10,17 @@ class Resource:
from_name is to be implemented by resource classes
"""
for T in cls.resource_types:
if r := T.from_name(name):
return r
return None
if T.resource_name == name:
return T
raise ValueError(f"No section type has name {name}")
def when(self, when_text):
pass
@classmethod
def from_section(cls, name, section):
parts = name.split(' ')
name = parts[0]
try:
label = parts[1]
except IndexError:
label = None
T = cls.from_name(name)
return T(label, section)

Loading…
Cancel
Save