diff --git a/.gitignore b/.gitignore
index e1f6aec..14c1cb5 100644
--- a/.gitignore
+++ b/.gitignore
@@ -27,3 +27,5 @@ screenlog*
__pycache__/
*.pyc
*test*.py
+*test*.sh
+*test*.exp
diff --git a/bdisk/confgen.py b/bdisk/confgen.py
index 74cbe92..cdf0e06 100755
--- a/bdisk/confgen.py
+++ b/bdisk/confgen.py
@@ -30,8 +30,8 @@ def pass_prompt(user):
_need_input_type = True
while _need_input_type:
_input_type = input('\nWill you be entering a password or a salted '
- 'hash? (If using a "special" value per the manual, '
- 'use 1 (password)):\n\n'
+ 'hash? (If using a "special" value per the '
+ 'manual, use password entry):\n\n'
'\t\t1: password\n'
'\t\t2: salted hash\n\n'
'Choice: ').strip()
@@ -576,7 +576,7 @@ class ConfGenerator(object):
usage = ('{0} for yes, {1} '
'for no...\n'))
return()
-
+
def get_build(self):
print('\n++ BUILD ++')
build = lxml.etree.SubElement(self.profile, 'build')
@@ -586,6 +586,7 @@ class ConfGenerator(object):
'{0} for yes, {1} for no...\n'))
if _chk_optimizations:
build.attrib['its_full_of_stars'] = 'yes'
+ print('\n++ BUILD || PATHS ++')
# Thankfully, we can simplify a lot of this.
_dir_strings = {'cache': ('the caching directory (used for temporary '
'files, temporary downloads, etc.)'),
@@ -625,6 +626,28 @@ class ConfGenerator(object):
_paths_elems[_dir].text = path
build.append(paths)
has_paths = True
+ print('\n++ BUILD || ENVIRONMENT DISTRO ++')
+ has_distro = False
+ while not has_distro:
+ try:
+ distro_path = self.profile.xpath('//paths/distros/text()')[0]
+ except IndexError:
+ distro_path = 'your "distros" path'
+ distro = (input('\nWhich distro plugin/distro base are you using? '
+ 'See the manual for more information. A matching '
+ 'plugin MUST exist in {0} for a build to '
+ 'complete successfully! The default (Arch Linux, '
+ '"archlinux") will be used if left blank.'
+ '\nDistro base: ').format(
+ distro_path)).strip()
+ if distro == '':
+ distro = 'archlinux'
+ if not valid.plugin_name(distro):
+ print('That is not a valid name. See the manual for examples '
+ 'and shipped plugins. Retrying.')
+ continue
+ distro_elem = lxml.etree.SubElement(build, 'distro')
+ distro_elem.text = distro
return()
def main():
diff --git a/bdisk/confparse.py b/bdisk/confparse.py
index 2e74073..def5ab7 100644
--- a/bdisk/confparse.py
+++ b/bdisk/confparse.py
@@ -1,49 +1,13 @@
-import _io
import copy
import re
import os
+import utils
import validators
-from urllib.parse import urlparse
import lxml.etree
+from urllib.parse import urlparse
etree = lxml.etree
-_profile_specifiers = ('id', 'name', 'uuid')
-
-def _detect_cfg(cfg):
- if isinstance(cfg, str):
- # check for path or string
- try:
- etree.fromstring(cfg.encode('utf-8'))
- return(cfg.encode('utf-8'))
- except lxml.etree.XMLSyntaxError:
- path = os.path.abspath(os.path.expanduser(cfg))
- try:
- with open(path, 'rb') as f:
- cfg = f.read()
- except FileNotFoundError:
- raise ValueError('Could not open {0}'.format(path))
- elif isinstance(cfg, _io.TextIOWrapper):
- _cfg = cfg.read().encode('utf-8')
- cfg.close()
- cfg = _cfg
- elif isinstance(self.cfg, _io.BufferedReader):
- _cfg = cfg.read()
- cfg.close()
- cfg = _cfg
- elif isinstance(cfg, bytes):
- return(cfg)
- else:
- raise TypeError('Could not determine the object type.')
- return(cfg)
-
-def _profile_xpath_gen(selector):
- xpath = ''
- for i in selector.items():
- if i[1] and i[0] in _profile_specifiers:
- xpath += '[@{0}="{1}"]'.format(*i)
- return(xpath)
-
class Conf(object):
def __init__(self, cfg, profile = None):
"""
@@ -80,7 +44,7 @@ class Conf(object):
# Mad props to https://stackoverflow.com/a/12728199/733214
self.xpath_re = re.compile('(?<=(?= self.max_recurse:
+ return(None)
+ if isinstance(element, lxml.etree._Element):
+ if isinstance(element, lxml.etree._Comment):
+ return(element)
+ if element.text:
+ _dictmap = self.xpath_to_dict(element.text)
+ while _dictmap:
+ for elem in _dictmap:
+ if _dictmap is None:
+ continue
+ # I still for the life of me cannot figure out why this
+ # is not caught by the above. But it isn't.
+ if elem not in _dictmap:
+ continue
+ if isinstance(_dictmap[elem], str):
+ try:
+ newpath = element.xpath(_dictmap[elem])
+ except (AttributeError, IndexError, TypeError):
+ newpath = element
+ try:
+ self.substitutions[elem] = self.substitute(
+ newpath,
+ (recurse_count + 1)
+ )[0]
+ except (IndexError, TypeError):
+ raise ValueError(
+ ('Encountered an error while trying to '
+ 'substitute {0} at {1}').format(
+ elem, self.get_path(element)
+ ))
+ element.text = XPathFmt().vformat(
+ element.text,
+ [],
+ self.substitutions)
+ _dictmap = self.xpath_to_dict(element.text)
+ return(element)
+
+ def xpath_selector(self, selectors,
+ selector_ids = ('id', 'name', 'uuid')):
+ # selectors is a dict of {attrib:value}
+ xpath = ''
+ for i in selectors.items():
+ if i[1] and i[0] in selector_ids:
+ xpath += '[@{0}="{1}"]'.format(*i)
+ return(xpath)
+
+ def xpath_to_dict(self, text_in):
+ d = None
+ ptrn_id = self.ptrn.findall(text_in)
+ if len(ptrn_id) >= 1:
+ for item in ptrn_id:
+ if not isinstance(d, dict):
+ d = {}
+ try:
+ _, xpath_expr = item.split('%', 1)
+ if not _ == 'xpath':
+ continue
+ if item not in self.substitutions:
+ self.substitutions[item] = None
+ d[item] = xpath_expr
+ except ValueError:
+ return(None)
+ return(d)
+
+
class valid(object):
def __init__(self):
pass
@@ -423,12 +554,9 @@ class valid(object):
pass
def email(self, addr):
- if isinstance(validators.email(emailparse(addr)[1]),
- validators.utils.ValidationFailure):
- return(False)
- else:
- return(True)
- return()
+ return(
+ isinstance(validators.email(emailparse(addr)[1]),
+ validators.utils.ValidationFailure))
def gpgkeyID(self, key_id):
# Condense fingerprints into normalized 40-char "full" key IDs.
@@ -487,14 +615,21 @@ class valid(object):
return(False)
return(True)
+ def plugin_name(self, name):
+ if len(name) == 0:
+ return(False)
+ _name_re = re.compile('^[a-z][0-9a-z_]+$', re.IGNORECASE)
+ if not _name_re.search(name):
+ return(False)
+ return(True)
+
def posix_filename(self, fname):
# Note: 2009 spec of POSIX, "3.282 Portable Filename Character Set"
if len(fname) == 0:
return(False)
- _chars = (string.ascii_letters + string.digits + '.-_')
- for char in fname:
- if char not in _chars:
- return(False)
+ _char_re = re.compile('^[a-z0-9._-]+$', re.IGNORECASE)
+ if not _char_re.search(fname):
+ return(False)
return(True)
def url(self, url):
diff --git a/docs/examples/multi_profile.xml b/docs/examples/multi_profile.xml
index b46ce87..9a77387 100644
--- a/docs/examples/multi_profile.xml
+++ b/docs/examples/multi_profile.xml
@@ -8,8 +8,9 @@
- {xpath_ref%../name/text()}
+ If you need a literal curly brace, double them (e.g. for "{foo}", use "{{foo}}"),
+ UNLESS it's in a {regex%...} placeholder/filter (as part of the expression). -->
+ {xpath%../name/text()}
A rescue/restore live environment.
@@ -19,7 +20,7 @@
https://domain.tld/projname
1.0.0
-
+
5
@@ -27,10 +28,10 @@
$6$7KfIdtHTcXwVrZAC$LZGNeMNz7v5o/cYuA48FAxtZynpIwO5B1CPGXnOW5kCTVpXVt4SypRqfM.AoKkFt/O7MZZ8ySXJmxpELKmdlF1
- {xpath_ref%//meta/names/uxname/text()}
+ {xpath%//meta/names/uxname/text()}
-
- {xpath_ref%//meta/dev/author/text()}
+
+ {xpath%//meta/dev/author/text()}
testpassword
@@ -43,100 +44,100 @@
- /var/tmp/{xpath_ref%//meta/names/uxname/text()}
- /var/tmp/chroots/{xpath_ref%//meta/names/uxname/text()}
- {xpath_ref%../cache/text()}/overlay
- ~/{xpath_ref%//meta/names/uxname/text()}/templates
- /mnt/{xpath_ref%//meta/names/uxname/text()}
- ~/{xpath_ref%//meta/names/uxname/text()}/distros
- ~/{xpath_ref%//meta/names/uxname/text()}/results
- {xpath_ref%../dest/text()}/iso
- {xpath_ref%../dest/text()}/http
- {xpath_ref%../dest/text()}/tftp
- {xpath_ref%../dest/text()}/pki
+ /var/tmp/{xpath%//meta/names/uxname/text()}
+ /var/tmp/chroots/{xpath%//meta/names/uxname/text()}
+ {xpath%../cache/text()}/overlay
+ ~/{xpath%//meta/names/uxname/text()}/templates
+ /mnt/{xpath%//meta/names/uxname/text()}
+ ~/{xpath%//meta/names/uxname/text()}/distros
+ ~/{xpath%//meta/names/uxname/text()}/results
+ {xpath%../dest/text()}/iso
+ {xpath%../dest/text()}/http
+ {xpath%../dest/text()}/tftp
+ {xpath%../dest/text()}/pki
archlinux
-
-
-
-
-
- {xpath_ref%//build/paths/ssl/text()}/ca.crt
-
-
- {xpath_ref%//build/paths/ssl/text()}/ca.key
-
- domain.tld
- XX
- Some City
- Some State
- Some Org, Inc.
- Department Name
- {xpath_ref%//meta/dev/email/text()}
-
-
-
- {xpath_ref%//build/paths/ssl/text()}/{xpath_ref%//meta/names/uxname/text()}.crt
-
- {xpath_ref%//build/paths/ssl/text()}/{xpath_ref%//meta/names/uxname/text()}.key
-
- domain.tld (client)
- XX
- Some City
- Some State
- Some Org, Inc.
- Department Name
- {xpath_ref%//meta/dev/email/text()}
-
-
-
- {xpath_ref%//meta/dev/website/text()}/ipxe
-
-
-
-
-
-
- root
- /srv/http/{xpath_ref%//meta/names/uxname/text()}
- mirror.domain.tld
- 22
- ~/.ssh/id_ed25519
-
-
+
+
+ {xpath%//meta/dev/website/text()}/ipxe
+
+
+
+
+ {xpath%../../../build/paths/pki/text()}/ca.crt
+
+
+ {xpath%../../../build/paths/pki/text()}/ca.key
+
+ domain.tld
+ XX
+ Some City
+ Some State
+ Some Org, Inc.
+ Department Name
+ {xpath%../../../../meta/dev/email/text()}
+
+
+
+ {xpath%../../../build/paths/pki/text()}/{xpath%../../../meta/names/uxname/text()}.crt
+
+ {xpath%//build/paths/pki/text()}/{xpath%../../../meta/names/uxname/text()}.key
+
+ some client name
+ XX
+ Some City
+ Some State
+ Some Org, Inc.
+ Department Name
+ {xpath%../../../../meta/dev/email/text()}
+
+
+
+
+
+ /srv/http/{xpath%../../meta/names/uxname/text()}
+ /tftproot/{xpath%../../meta/names/uxname/text()}
+ /srv/http/isos/{xpath%../../meta/names/uxname/text()}
+
+ root
+ mirror.domain.tld
+ 22
+ ~/.ssh/id_ed25519
+
+
AnotherCD
bdisk_alt
- {xpath_ref%../name/text()}
+ {xpath%../name/text()}
Another rescue/restore live environment.
Another Dev Eloper
- {xpath_ref%//profile[@name="default"]/meta/dev/email/text()}
- {xpath_ref%//profile[@name="default"]/meta/dev/website/text()}
+ {xpath%//profile[@name="default"]/meta/dev/email/text()}
+ {xpath%//profile[@name="default"]/meta/dev/website/text()}
https://domain.tld/projname
0.0.1
@@ -154,79 +155,79 @@
- /var/tmp/{xpath_ref%//meta/names/uxname/text()}
- /var/tmp/chroots/{xpath_ref%//meta/names/uxname/text()}
- {xpath_ref%../cache/text()}/overlay
- ~/{xpath_ref%//meta/names/uxname/text()}/templates
- /mnt/{xpath_ref%//meta/names/uxname/text()}
- ~/{xpath_ref%//meta/names/uxname/text()}/distros
- ~/{xpath_ref%//meta/names/uxname/text()}/results
- {xpath_ref%../dest/text()}/iso
- {xpath_ref%../dest/text()}/http
- {xpath_ref%../dest/text()}/tftp
- {xpath_ref%../dest/text()}/pki
+ /var/tmp/{xpath%//meta/names/uxname/text()}
+ /var/tmp/chroots/{xpath%//meta/names/uxname/text()}
+ {xpath%../cache/text()}/overlay
+ ~/{xpath%//meta/names/uxname/text()}/templates
+ /mnt/{xpath%//meta/names/uxname/text()}
+ ~/{xpath%//meta/names/uxname/text()}/distros
+ ~/{xpath%//meta/names/uxname/text()}/results
+ {xpath%../dest/text()}/iso
+ {xpath%../dest/text()}/http
+ {xpath%../dest/text()}/tftp
+ {xpath%../dest/text()}/pki
archlinux
-
-
-
-
- {xpath_ref%//build/paths/ssl/text()}/ca.crt
-
- {xpath_ref%//build/paths/ssl/text()}/ca.key
-
- domain.tld
- XX
- Some City
- Some State
- Some Org, Inc.
- Department Name
- {xpath_ref%//meta/dev/email/text()}
-
-
-
- {xpath_ref%//build/paths/ssl/text()}/{xpath_ref%//meta/names/uxname/text()}.crt
-
- {xpath_ref%//build/paths/ssl/text()}/{xpath_ref%//meta/names/uxname/text()}.key
-
- domain.tld (client)
- XX
- Some City
- Some State
- Some Org, Inc.
- Department Name
- {xpath_ref%//meta/dev/email/text()}
-
-
-
- {xpath_ref%//meta/dev/website/text()}/ipxe
-
-
-
-
-
-
- root
- /srv/http/{xpath_ref%//meta/names/uxname/text()}
- mirror.domain.tld
- 22
- ~/.ssh/id_ed25519
-
-
+
+
+ {xpath%//meta/dev/website/text()}/ipxe
+
+
+
+ {xpath%../../../build/paths/pki/text()}/ca.crt
+
+ {xpath%../../../build/paths/pki/text()}/ca.key
+
+ domain.tld
+ XX
+ Some City
+ Some State
+ Some Org, Inc.
+ Department Name
+ {xpath%../../../../meta/dev/email/text()}
+
+
+
+ {xpath%../../../build/paths/pki/text()}/{xpath%../../../meta/names/uxname/text()}.crt
+
+ {xpath%//build/paths/pki/text()}/{xpath%../../../meta/names/uxname/text()}.key
+
+ some client name
+ XX
+ Some City
+ Some State
+ Some Org, Inc.
+ Department Name
+ {xpath%../../../../meta/dev/email/text()}
+
+
+
+
+
+ /srv/http/{xpath%../../meta/names/uxname/text()}
+ /tftproot/{xpath%../../meta/names/uxname/text()}
+ /srv/http/isos/{xpath%../../meta/names/uxname/text()}
+
+ root
+ mirror.domain.tld
+ 22
+ ~/.ssh/id_ed25519
+
+
diff --git a/docs/examples/regen_multi.py b/docs/examples/regen_multi.py
index ff3cc50..e2673ca 100755
--- a/docs/examples/regen_multi.py
+++ b/docs/examples/regen_multi.py
@@ -19,11 +19,11 @@ alt_profile.attrib['uuid'] = '2ed07c19-2071-4d66-8569-da40475ba716'
meta_tags = {'name': 'AnotherCD',
'uxname': 'bdisk_alt',
- 'pname': '{xpath_ref%../name/text()}',
+ 'pname': '{xpath%../name/text()}',
'desc': 'Another rescue/restore live environment.',
'author': 'Another Dev Eloper',
- 'email': '{xpath_ref%//profile[@name="default"]/meta/dev/email/text()}',
- 'website': '{xpath_ref%//profile[@name="default"]/meta/dev/website/text()}',
+ 'email': '{xpath%//profile[@name="default"]/meta/dev/email/text()}',
+ 'website': '{xpath%//profile[@name="default"]/meta/dev/website/text()}',
'ver': '0.0.1'}
# Change the names
meta = alt_profile.xpath('/profile/meta')[0]
diff --git a/docs/examples/single_profile.xml b/docs/examples/single_profile.xml
index 465a737..f0ce144 100644
--- a/docs/examples/single_profile.xml
+++ b/docs/examples/single_profile.xml
@@ -8,8 +8,9 @@
- {xpath_ref%../name/text()}
+ If you need a literal curly brace, double them (e.g. for "{foo}", use "{{foo}}"),
+ UNLESS it's in a {regex%...} placeholder/filter (as part of the expression). -->
+ {xpath%../name/text()}
A rescue/restore live environment.
@@ -19,7 +20,7 @@
https://domain.tld/projname
1.0.0
-
+
5
@@ -27,10 +28,10 @@
$6$7KfIdtHTcXwVrZAC$LZGNeMNz7v5o/cYuA48FAxtZynpIwO5B1CPGXnOW5kCTVpXVt4SypRqfM.AoKkFt/O7MZZ8ySXJmxpELKmdlF1
- {xpath_ref%//meta/names/uxname/text()}
+ {xpath%//meta/names/uxname/text()}
-
- {xpath_ref%//meta/dev/author/text()}
+
+ {xpath%//meta/dev/author/text()}
testpassword
@@ -47,89 +48,89 @@
- /var/tmp/{xpath_ref%//meta/names/uxname/text()}
- /var/tmp/chroots/{xpath_ref%//meta/names/uxname/text()}
- {xpath_ref%../cache/text()}/overlay
- ~/{xpath_ref%//meta/names/uxname/text()}/templates
- /mnt/{xpath_ref%//meta/names/uxname/text()}
- ~/{xpath_ref%//meta/names/uxname/text()}/distros
- ~/{xpath_ref%//meta/names/uxname/text()}/results
- {xpath_ref%../dest/text()}/iso
- {xpath_ref%../dest/text()}/http
- {xpath_ref%../dest/text()}/tftp
- {xpath_ref%../dest/text()}/pki
+ /var/tmp/{xpath%//meta/names/uxname/text()}
+ /var/tmp/chroots/{xpath%//meta/names/uxname/text()}
+ {xpath%../cache/text()}/overlay
+ ~/{xpath%//meta/names/uxname/text()}/templates
+ /mnt/{xpath%//meta/names/uxname/text()}
+ ~/{xpath%//meta/names/uxname/text()}/distros
+ ~/{xpath%//meta/names/uxname/text()}/results
+ {xpath%../dest/text()}/iso
+ {xpath%../dest/text()}/http
+ {xpath%../dest/text()}/tftp
+ {xpath%../dest/text()}/pki
archlinux
-
-
-
-
-
- {xpath_ref%//build/paths/ssl/text()}/ca.crt
-
-
- {xpath_ref%//build/paths/ssl/text()}/ca.key
-
- domain.tld
- XX
- Some City
- Some State
- Some Org, Inc.
- Department Name
- {xpath_ref%//meta/dev/email/text()}
-
-
-
- {xpath_ref%//build/paths/ssl/text()}/{xpath_ref%//meta/names/uxname/text()}.crt
-
- {xpath_ref%//build/paths/ssl/text()}/{xpath_ref%//meta/names/uxname/text()}.key
-
- domain.tld (client)
- XX
- Some City
- Some State
- Some Org, Inc.
- Department Name
- {xpath_ref%//meta/dev/email/text()}
-
-
-
- {xpath_ref%//meta/dev/website/text()}/ipxe
-
-
-
-
-
-
- root
- /srv/http/{xpath_ref%//meta/names/uxname/text()}
- mirror.domain.tld
- 22
- ~/.ssh/id_ed25519
-
-
+
+
+ {xpath%//meta/dev/website/text()}/ipxe
+
+
+
+
+ {xpath%../../../build/paths/pki/text()}/ca.crt
+
+
+ {xpath%../../../build/paths/pki/text()}/ca.key
+
+ domain.tld
+ XX
+ Some City
+ Some State
+ Some Org, Inc.
+ Department Name
+ {xpath%../../../../meta/dev/email/text()}
+
+
+
+ {xpath%../../../build/paths/pki/text()}/{xpath%../../../meta/names/uxname/text()}.crt
+
+ {xpath%//build/paths/pki/text()}/{xpath%../../../meta/names/uxname/text()}.key
+
+ some client name
+ XX
+ Some City
+ Some State
+ Some Org, Inc.
+ Department Name
+ {xpath%../../../../meta/dev/email/text()}
+
+
+
+
+
+ /srv/http/{xpath%../../meta/names/uxname/text()}
+ /tftproot/{xpath%../../meta/names/uxname/text()}
+ /srv/http/isos/{xpath%../../meta/names/uxname/text()}
+
+ root
+ mirror.domain.tld
+ 22
+ ~/.ssh/id_ed25519
+
+