Skip to content

Commit

Permalink
Merge pull request #246 from psyinfra/rf-init
Browse files Browse the repository at this point in the history
NF/TST: add `repo(init=bool)`, and assorted test modernization
  • Loading branch information
aqw authored Nov 2, 2022
2 parents 13a42b6 + 2439690 commit 17bd5fb
Show file tree
Hide file tree
Showing 10 changed files with 465 additions and 344 deletions.
83 changes: 13 additions & 70 deletions onyo/commands/init.py
Original file line number Diff line number Diff line change
@@ -1,85 +1,28 @@
import logging
import sys
import shutil
from pathlib import Path
import git
from onyo import Repo

logging.basicConfig()
log = logging.getLogger('onyo')


def get_skel_dir():
"""
Return the path of the skel/ dir in the onyo module directory.
"""
onyo_module_dir = Path(__file__).resolve().parent.parent
skel = Path(onyo_module_dir, 'skel')
return skel


def sanitize_dir(directory, opdir):
"""
Check the directory for viability as an init target.
Returns the absolute path on success.
"""
full_dir = Path(opdir)
if directory:
full_dir = Path(opdir, directory)

# sanity checks
# already an .onyo repo
dot_onyo = full_dir.joinpath('.onyo')
if dot_onyo.is_dir():
log.error(f"'{dot_onyo}' already exists. Exiting.")
sys.exit(1)

# target is a file, etc
if full_dir.exists() and not full_dir.is_dir():
log.error(f"'{full_dir}' exists but is not a directory. Exiting.")
sys.exit(1)

# make sure parent exists
if not full_dir.is_dir():
parent_dir = full_dir.parent
if not parent_dir.is_dir():
log.error(f"'{parent_dir}' does not exist. Exiting.")
sys.exit(1)

abs_dir = str(full_dir.resolve())
return abs_dir


def init(args, opdir):
def init(args, opdir: str) -> None:
"""
Initialize an Onyo repository. The directory will be initialized as a git
repository (if it is not one already), the ``.onyo/`` directory created
(containing default config files, templates, etc), and everything committed.
repository (if it is not one already), the ``.onyo/`` directory created and
populated with config files, templates, etc. Everything will be committed.
The current working directory will be initialized if neither ``directory``
nor the ``onyo -C <dir>`` option are specified.
Running ``onyo init`` on an existing repository is safe. It will not
overwrite anything; it will exit with an error.
"""
target_dir = sanitize_dir(args.directory, opdir)
Path(target_dir).mkdir(exist_ok=True)
target_dir = Path(opdir)
if args.directory:
if Path(args.directory).is_absolute():
target_dir = Path(args.directory)
else:
target_dir = Path(opdir, args.directory)

try:
repo = git.Repo(target_dir)
log.info(target_dir + " has a git repository.")
except git.exc.InvalidGitRepositoryError:
repo = git.Repo.init(target_dir)

# populate .onyo dir
skel = get_skel_dir()
dot_onyo = Path(target_dir, ".onyo")
shutil.copytree(skel, dot_onyo)

# add and commit
repo.git.add('.onyo/')
repo.git.commit(m='initialize onyo repository')

# print success
abs_dot_onyo = str(dot_onyo.resolve())
print(f'Initialized Onyo repository in {abs_dot_onyo}')
Repo(target_dir, init=True)
except (FileExistsError, FileNotFoundError):
sys.exit(1)
75 changes: 73 additions & 2 deletions onyo/lib/onyo.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import logging
import random
import re
import shutil
import string
import subprocess
from pathlib import Path
Expand All @@ -23,7 +24,10 @@ class OnyoProtectedPathError(Exception):
class Repo:
"""
"""
def __init__(self, path: Union[Path, str]) -> None:
def __init__(self, path: Union[Path, str], init: bool = False) -> None:
if init:
self._init(path)

self._opdir = Path(path).resolve()
self._root = self._get_root()
# caches
Expand Down Expand Up @@ -445,6 +449,68 @@ def _fsck_yaml(self) -> bool:

return True

#
# INIT
#
def _init(self, directory: Union[Path, str]) -> None:
"""
Initialize an Onyo repository. The directory will be initialized as a
git repository (if it is not one already), ``.onyo/`` directory created
(containing default config files, templates, etc), and everything
committed.
Re-init-ing an existing repository is safe. It will not overwrite
anything; it will raise an exception.
"""
target_dir = self._init_sanitize(directory)
skel_dir = Path(Path(__file__).resolve().parent.parent, 'skel')
dot_onyo = Path(target_dir, '.onyo')

# create target if it doesn't already exist
target_dir.mkdir(exist_ok=True)

# git init (if needed)
if Path(target_dir, '.git').exists():
log.info(f"'{target_dir}' is already a git repository.")
else:
ret = self._git(['init'], cwd=target_dir)
log.info(ret.strip())

# populate .onyo dir
shutil.copytree(skel_dir, dot_onyo)

# add and commit
self._git(['add', '.onyo/'], cwd=target_dir)
self._git(['commit', '-m', 'Initialize as an Onyo repository'], cwd=target_dir)

log.info(f'Initialized Onyo repository in {dot_onyo}/')

def _init_sanitize(self, directory: Union[Path, str]) -> Path:
"""
Check the target path for viability as an init target.
Returns an absolute Path on success.
"""
full_path = Path(directory).resolve()

# target must be a directory
if full_path.exists() and not full_path.is_dir():
log.error(f"'{full_path}' exists but is not a directory.")
raise FileExistsError(f"'{full_path}' exists but is not a directory.")

# parent must exist
if not full_path.parent.exists():
log.error(f"'{full_path.parent}' does not exist.")
raise FileNotFoundError(f"'{full_path.parent}' does not exist.")

# cannot already be an .onyo repo
dot_onyo = Path(full_path, '.onyo')
if dot_onyo.exists():
log.error(f"'{dot_onyo}' already exists.")
raise FileExistsError(f"'{dot_onyo}' already exists.")

return full_path

#
# MKDIR
#
Expand Down Expand Up @@ -751,7 +817,12 @@ def generate_faux_serials(self, length: int = 6, num: int = 1) -> set[str]:
if length < 4:
# 62^4 is ~14.7 million combinations. Which is the lowest acceptable
# risk of collisions between independent checkouts of a repo.
raise ValueError('The length of faux serial numbers must be greater than 4.')
raise ValueError('The length of faux serial numbers must be >= 4.')

if num < 1:
# 62^4 is ~14.7 million combinations. Which is the lowest acceptable
# risk of collisions between independent checkouts of a repo.
raise ValueError('The length of faux serial numbers must be >= 1.')

alphanum = string.ascii_letters + string.digits
faux_serials = set()
Expand Down
1 change: 0 additions & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
packages=find_packages(),
license='ISC',
install_requires=[
'GitPython',
'ruamel.yaml'
],
extras_require={
Expand Down
Loading

0 comments on commit 17bd5fb

Please sign in to comment.