checking in some major progress. STILL hitting a bug with multiple xpath% btags(TM ;P) with a regex% tag in the same line that contains {#}.

This commit is contained in:
brent s. 2018-05-15 05:31:20 -04:00
parent befcd8185e
commit ed7ccdeeaf
7 changed files with 396 additions and 270 deletions

2
.gitignore vendored
View File

@ -27,3 +27,5 @@ screenlog*
__pycache__/ __pycache__/
*.pyc *.pyc
*test*.py *test*.py
*test*.sh
*test*.exp

View File

@ -30,8 +30,8 @@ def pass_prompt(user):
_need_input_type = True _need_input_type = True
while _need_input_type: while _need_input_type:
_input_type = input('\nWill you be entering a password or a salted ' _input_type = input('\nWill you be entering a password or a salted '
'hash? (If using a "special" value per the manual, ' 'hash? (If using a "special" value per the '
'use 1 (password)):\n\n' 'manual, use password entry):\n\n'
'\t\t1: password\n' '\t\t1: password\n'
'\t\t2: salted hash\n\n' '\t\t2: salted hash\n\n'
'Choice: ').strip() 'Choice: ').strip()
@ -576,7 +576,7 @@ class ConfGenerator(object):
usage = ('{0} for yes, {1} ' usage = ('{0} for yes, {1} '
'for no...\n')) 'for no...\n'))
return() return()

def get_build(self): def get_build(self):
print('\n++ BUILD ++') print('\n++ BUILD ++')
build = lxml.etree.SubElement(self.profile, 'build') build = lxml.etree.SubElement(self.profile, 'build')
@ -586,6 +586,7 @@ class ConfGenerator(object):
'{0} for yes, {1} for no...\n')) '{0} for yes, {1} for no...\n'))
if _chk_optimizations: if _chk_optimizations:
build.attrib['its_full_of_stars'] = 'yes' build.attrib['its_full_of_stars'] = 'yes'
print('\n++ BUILD || PATHS ++')
# Thankfully, we can simplify a lot of this. # Thankfully, we can simplify a lot of this.
_dir_strings = {'cache': ('the caching directory (used for temporary ' _dir_strings = {'cache': ('the caching directory (used for temporary '
'files, temporary downloads, etc.)'), 'files, temporary downloads, etc.)'),
@ -625,6 +626,28 @@ class ConfGenerator(object):
_paths_elems[_dir].text = path _paths_elems[_dir].text = path
build.append(paths) build.append(paths)
has_paths = True 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() return()


def main(): def main():

View File

@ -1,49 +1,13 @@
import _io
import copy import copy
import re import re
import os import os
import utils
import validators import validators
from urllib.parse import urlparse
import lxml.etree import lxml.etree
from urllib.parse import urlparse


etree = lxml.etree 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): class Conf(object):
def __init__(self, cfg, profile = None): def __init__(self, cfg, profile = None):
""" """
@ -80,7 +44,7 @@ class Conf(object):
# Mad props to https://stackoverflow.com/a/12728199/733214 # Mad props to https://stackoverflow.com/a/12728199/733214
self.xpath_re = re.compile('(?<=(?<!\{)\{)[^{}]*(?=\}(?!\}))') self.xpath_re = re.compile('(?<=(?<!\{)\{)[^{}]*(?=\}(?!\}))')
self.substitutions = {} self.substitutions = {}
self.xpaths = ['xpath_ref'] self.xpaths = ['xpath']
try: try:
self.xml = etree.fromstring(self.raw) self.xml = etree.fromstring(self.raw)
except lxml.etree.XMLSyntaxError: except lxml.etree.XMLSyntaxError:

View File

@ -1,8 +1,10 @@
import _io
import crypt import crypt
import GPG import GPG
import hashid import hashid
import hashlib import hashlib
import os import os
import pprint
import re import re
import string import string
import textwrap import textwrap
@ -31,6 +33,15 @@ crypt_map = {'sha512': crypt.METHOD_SHA512,
'md5': crypt.METHOD_MD5, 'md5': crypt.METHOD_MD5,
'des': crypt.METHOD_CRYPT} 'des': crypt.METHOD_CRYPT}


class XPathFmt(string.Formatter):
def get_field(self, field_name, args, kwargs):
vals = self.get_value(field_name, args, kwargs), field_name
if not vals[0]:
print(vals)
vals = ('{{{0}}}'.format(vals[1]), vals[1])
print(vals)
return(vals)

class detect(object): class detect(object):
def __init__(self): def __init__(self):
pass pass
@ -411,6 +422,126 @@ class transform(object):
url['full_url'] += '#{0}'.format('#'.join(_f)) url['full_url'] += '#{0}'.format('#'.join(_f))
return(url) return(url)


class xml_supplicant(object):
def __init__(self, cfg, profile = None, max_recurse = 5):
raw = self._detect_cfg(cfg)
xmlroot = lxml.etree.fromstring(raw)
self.root = lxml.etree.ElementTree(xmlroot)
self.max_recurse = max_recurse
self.ptrn = re.compile('(?<=(?<!\{)\{)[^{}]*(?=\}(?!\}))')
self.substitutions = {}
if not profile:
self.profile = xmlroot.xpath('/bdisk/profile[1]')[0]
else:
self.profile = xmlroot.xpath(profile)[0]
def _detect_cfg(self, cfg):
if isinstance(cfg, str):
try:
lxml.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(cfg, _io.BufferedReader):
_cfg = cfg.read()
cfg.close()
cfg = _cfg
elif isinstance(cfg, lxml.etree._Element):
return(lxml.etree.tostring(cfg))
elif isinstance(cfg, bytes):
return(cfg)
else:
raise TypeError('Could not determine the object type.')
return(cfg)

def get_path(self, element):
path = element
try:
path = self.root.getpath(element)
except ValueError:
raise ValueError(
(
'Could not find a path for the expression {0}'
).format(element.text))
return(path)

def substitute(self, element, recurse_count = 0):
if recurse_count >= 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): class valid(object):
def __init__(self): def __init__(self):
pass pass
@ -423,12 +554,9 @@ class valid(object):
pass pass


def email(self, addr): def email(self, addr):
if isinstance(validators.email(emailparse(addr)[1]), return(
validators.utils.ValidationFailure): isinstance(validators.email(emailparse(addr)[1]),
return(False) validators.utils.ValidationFailure))
else:
return(True)
return()


def gpgkeyID(self, key_id): def gpgkeyID(self, key_id):
# Condense fingerprints into normalized 40-char "full" key IDs. # Condense fingerprints into normalized 40-char "full" key IDs.
@ -487,14 +615,21 @@ class valid(object):
return(False) return(False)
return(True) 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): def posix_filename(self, fname):
# Note: 2009 spec of POSIX, "3.282 Portable Filename Character Set" # Note: 2009 spec of POSIX, "3.282 Portable Filename Character Set"
if len(fname) == 0: if len(fname) == 0:
return(False) return(False)
_chars = (string.ascii_letters + string.digits + '.-_') _char_re = re.compile('^[a-z0-9._-]+$', re.IGNORECASE)
for char in fname: if not _char_re.search(fname):
if char not in _chars: return(False)
return(False)
return(True) return(True)


def url(self, url): def url(self, url):

View File

@ -8,8 +8,9 @@
<!-- Just like with previous versions of BDisk, you can reference other values... <!-- Just like with previous versions of BDisk, you can reference other values...
but now with the neat benefits of XPath! Everything you could do in build.ini's and more. but now with the neat benefits of XPath! Everything you could do in build.ini's and more.
See https://www.w3schools.com/xml/xpath_syntax.asp See https://www.w3schools.com/xml/xpath_syntax.asp
If you need a literal bracket, double them (e.g. for "{foo}", use "{{foo}}") --> If you need a literal curly brace, double them (e.g. for "{foo}", use "{{foo}}"),
<pname>{xpath_ref%../name/text()}</pname> UNLESS it's in a {regex%...} placeholder/filter (as part of the expression). -->
<pname>{xpath%../name/text()}</pname>
</names> </names>
<desc>A rescue/restore live environment.</desc> <desc>A rescue/restore live environment.</desc>
<dev> <dev>
@ -19,7 +20,7 @@
</dev> </dev>
<uri>https://domain.tld/projname</uri> <uri>https://domain.tld/projname</uri>
<ver>1.0.0</ver> <ver>1.0.0</ver>
<!-- This is the VERY FIRST value parsed, and is required. It controls how many levels of {xpath_ref%...} to recurse. --> <!-- This is the VERY FIRST value parsed, and is required. It controls how many levels of {xpath%...} to recurse. -->
<!-- If the maximum level is reached, the substitution will evaluate as blank. --> <!-- If the maximum level is reached, the substitution will evaluate as blank. -->
<max_recurse>5</max_recurse> <max_recurse>5</max_recurse>
</meta> </meta>
@ -27,10 +28,10 @@
<!-- Salted/hashed password is "test" --> <!-- Salted/hashed password is "test" -->
<rootpass hashed="yes">$6$7KfIdtHTcXwVrZAC$LZGNeMNz7v5o/cYuA48FAxtZynpIwO5B1CPGXnOW5kCTVpXVt4SypRqfM.AoKkFt/O7MZZ8ySXJmxpELKmdlF1</rootpass> <rootpass hashed="yes">$6$7KfIdtHTcXwVrZAC$LZGNeMNz7v5o/cYuA48FAxtZynpIwO5B1CPGXnOW5kCTVpXVt4SypRqfM.AoKkFt/O7MZZ8ySXJmxpELKmdlF1</rootpass>
<user sudo="yes"> <user sudo="yes">
<username>{xpath_ref%//meta/names/uxname/text()}</username> <username>{xpath%//meta/names/uxname/text()}</username>
<!-- You can also use substitution from different profiles: --> <!-- You can also use substitution from different profiles: -->
<!-- <username>{xpath_ref%//profile[@name='another_profile']/meta/names/uxname"}</username> --> <!-- <username>{xpath%//profile[@name='another_profile']/meta/names/uxname"}</username> -->
<comment>{xpath_ref%//meta/dev/author/text()}</comment> <comment>{xpath%//meta/dev/author/text()}</comment>
<password hashed="no" hash_algo="sha512" salt="auto">testpassword</password> <password hashed="no" hash_algo="sha512" salt="auto">testpassword</password>
</user> </user>
<user sudo="no"> <user sudo="no">
@ -43,100 +44,100 @@
<source arch="x86_64"> <source arch="x86_64">
<mirror>http://archlinux.mirror.domain.tld</mirror> <mirror>http://archlinux.mirror.domain.tld</mirror>
<webroot>/iso/latest</webroot> <webroot>/iso/latest</webroot>
<tarball flags="latest">{xpath_ref%../mirror/text()}{xpath_ref%../webroot/text()}/{regex%archlinux-bootstrap-[0-9]{4}\.[0-9]{2}\.[0-9]{2}-x86_64\.tar\.gz}</tarball> <tarball flags="regex,latest">{xpath%../mirror/text()}{xpath%../webroot/text()}/{regex%archlinux-bootstrap-[0-9]{4}\.[0-9]{2}\.[0-9]{2}-x86_64\.tar\.gz}</tarball>
<checksum hash_algo="sha1" flags="none">{xpath_ref%../mirror/text()}{xpath_ref%../webroot/text()}/sha1sums.txt</checksum> <checksum hash_algo="sha1" flags="none">{xpath%../mirror/text()}{xpath%../webroot/text()}/sha1sums.txt</checksum>
<sig keys="7F2D434B9741E8AC" keyserver="hkp://pool.sks-keyservers.net" flags="latest">{xpath_ref%../tarball/text()}.sig</sig> <sig keys="7F2D434B9741E8AC" keyserver="hkp://pool.sks-keyservers.net" flags="latest">{xpath%../tarball/text()}.sig</sig>
</source> </source>
<source arch="i686"> <source arch="i686">
<mirror>http://archlinux32.mirror.domain.tld</mirror> <mirror>http://archlinux32.mirror.domain.tld</mirror>
<webroot>/iso/latest</webroot> <webroot>/iso/latest</webroot>
<tarball flag="regex,latest">{xpath_ref%../mirror/text()}/{xpath_ref%../webroot/text()}/{regex%archlinux-bootstrap-[0-9]{4}\.[0-9]{2}\.[0-9]{2}-i686\.tar\.gz}</tarball> <tarball flag="regex,latest">{xpath%../mirror/text()}/{xpath%../webroot/text()}/{regex%archlinux-bootstrap-[0-9]{4}\.[0-9]{2}\.[0-9]{2}-i686\.tar\.gz}</tarball>
<checksum hash_algo="sha512" explicit="yes">cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e</checksum> <checksum hash_algo="sha512" explicit="yes">cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e</checksum>
<sig keys="248BF41F9BDD61D41D060AE774EDA3C6B06D0506" keyserver="hkp://pool.sks-keyservers.net">{xpath_ref%../tarball/text()}.sig</sig> <sig keys="248BF41F9BDD61D41D060AE774EDA3C6B06D0506" keyserver="hkp://pool.sks-keyservers.net">{xpath%../tarball/text()}.sig</sig>
</source> </source>
</sources> </sources>
<build its_full_of_stars="yes"> <build its_full_of_stars="yes">
<paths> <paths>
<cache>/var/tmp/{xpath_ref%//meta/names/uxname/text()}</cache> <cache>/var/tmp/{xpath%//meta/names/uxname/text()}</cache>
<chroot>/var/tmp/chroots/{xpath_ref%//meta/names/uxname/text()}</chroot> <chroot>/var/tmp/chroots/{xpath%//meta/names/uxname/text()}</chroot>
<overlay>{xpath_ref%../cache/text()}/overlay</overlay> <overlay>{xpath%../cache/text()}/overlay</overlay>
<templates>~/{xpath_ref%//meta/names/uxname/text()}/templates</templates> <templates>~/{xpath%//meta/names/uxname/text()}/templates</templates>
<mount>/mnt/{xpath_ref%//meta/names/uxname/text()}</mount> <mount>/mnt/{xpath%//meta/names/uxname/text()}</mount>
<distros>~/{xpath_ref%//meta/names/uxname/text()}/distros</distros> <distros>~/{xpath%//meta/names/uxname/text()}/distros</distros>
<dest>~/{xpath_ref%//meta/names/uxname/text()}/results</dest> <dest>~/{xpath%//meta/names/uxname/text()}/results</dest>
<iso>{xpath_ref%../dest/text()}/iso</iso> <iso>{xpath%../dest/text()}/iso</iso>
<http>{xpath_ref%../dest/text()}/http</http> <http>{xpath%../dest/text()}/http</http>
<tftp>{xpath_ref%../dest/text()}/tftp</tftp> <tftp>{xpath%../dest/text()}/tftp</tftp>
<ssl>{xpath_ref%../dest/text()}/pki</ssl> <pki>{xpath%../dest/text()}/pki</pki>
</paths> </paths>
<basedistro>archlinux</basedistro> <basedistro>archlinux</basedistro>
<iso sign="yes" sync="yes" multiarch="yes" rsync="yes"/>
<ipxe sign="yes" sync="yes" iso="yes" rsync="yes">
<ssl custom="no">
<!-- http://ipxe.org/crypto -->
<ca>
<cert>{xpath_ref%//build/paths/ssl/text()}/ca.crt</cert>
<!-- If csr is self-enclosed (<csr />), we'll just generate and use a CSR in-memory.
Assuming we need to generate a certificate, anyways.
If you want to write it out to disk (for debugging, etc.) OR use one already generated,
then provide a path.
e.g.:
<csr>{xpath_ref%build/paths/ssl/text()}/ca.csr</csr> -->
<csr/>
<key des="no" passphrase="none">{xpath_ref%//build/paths/ssl/text()}/ca.key</key>
<subject>
<commonName>domain.tld</commonName>
<countryName>XX</countryName>
<localityName>Some City</localityName>
<stateOrProvinceName>Some State</stateOrProvinceName>
<organization>Some Org, Inc.</organization>
<organizationalUnitName>Department Name</organizationalUnitName>
<emailAddress>{xpath_ref%//meta/dev/email/text()}</emailAddress>
</subject>
</ca>
<server>
<cert>{xpath_ref%//build/paths/ssl/text()}/{xpath_ref%//meta/names/uxname/text()}.crt</cert>
<csr/>
<key des="no" passphrase="none">{xpath_ref%//build/paths/ssl/text()}/{xpath_ref%//meta/names/uxname/text()}.key</key>
<subject>
<commonName>domain.tld (client)</commonName>
<countryName>XX</countryName>
<localityName>Some City</localityName>
<stateOrProvinceName>Some State</stateOrProvinceName>
<organization>Some Org, Inc.</organization>
<organizationalUnitName>Department Name</organizationalUnitName>
<emailAddress>{xpath_ref%//meta/dev/email/text()}</emailAddress>
</subject>
</server>
</ssl>
<uri>{xpath_ref%//meta/dev/website/text()}/ipxe</uri>
</ipxe>
<gpg keyid="none" gnupghome="none" publish="no" sync="yes"/>
<sync>
<http enabled="yes" rsync="yes"/>
<tftp enabled="yes" rsync="yes"/>
<rsync enabled="yes">
<user>root</user>
<path>/srv/http/{xpath_ref%//meta/names/uxname/text()}</path>
<host>mirror.domain.tld</host>
<port>22</port>
<pubkey>~/.ssh/id_ed25519</pubkey>
</rsync>
</sync>
</build> </build>
<iso sign="yes" multiarch="yes"/>
<ipxe sign="yes" iso="yes">
<uri>{xpath%//meta/dev/website/text()}/ipxe</uri>
</ipxe>
<pki overwrite="no">
<!-- http://ipxe.org/crypto -->
<ca>
<cert>{xpath%../../../build/paths/pki/text()}/ca.crt</cert>
<!-- If csr is self-enclosed (<csr />), we'll just generate and use a CSR in-memory.
Assuming we need to generate a certificate, anyways.
If you want to write it out to disk (for debugging, etc.) OR use one already generated,
then provide a path.
e.g.:
<csr>{xpath%build/paths/ssl/text()}/ca.csr</csr> -->
<csr/>
<key des="no" passphrase="none">{xpath%../../../build/paths/pki/text()}/ca.key</key>
<subject>
<commonName>domain.tld</commonName>
<countryName>XX</countryName>
<localityName>Some City</localityName>
<stateOrProvinceName>Some State</stateOrProvinceName>
<organization>Some Org, Inc.</organization>
<organizationalUnitName>Department Name</organizationalUnitName>
<emailAddress>{xpath%../../../../meta/dev/email/text()}</emailAddress>
</subject>
</ca>
<client>
<cert>{xpath%../../../build/paths/pki/text()}/{xpath%../../../meta/names/uxname/text()}.crt</cert>
<csr/>
<key des="no" passphrase="none">{xpath%//build/paths/pki/text()}/{xpath%../../../meta/names/uxname/text()}.key</key>
<subject>
<commonName>some client name</commonName>
<countryName>XX</countryName>
<localityName>Some City</localityName>
<stateOrProvinceName>Some State</stateOrProvinceName>
<organization>Some Org, Inc.</organization>
<organizationalUnitName>Department Name</organizationalUnitName>
<emailAddress>{xpath%../../../../meta/dev/email/text()}</emailAddress>
</subject>
</client>
</pki>
<gpg keyid="none" gnupghome="none" publish="no" sync="yes"/>
<sync>
<ipxe enabled="yes" rsync="yes">/srv/http/{xpath%../../meta/names/uxname/text()}</ipxe>
<tftp enabled="yes" rsync="yes">/tftproot/{xpath%../../meta/names/uxname/text()}</tftp>
<iso enabled="yes" rsync="yes">/srv/http/isos/{xpath%../../meta/names/uxname/text()}</iso>
<rsync enabled="yes">
<user>root</user>
<host>mirror.domain.tld</host>
<port>22</port>
<pubkey>~/.ssh/id_ed25519</pubkey>
</rsync>
</sync>
</profile> </profile>
<profile name="alternate" id="2" uuid="2ed07c19-2071-4d66-8569-da40475ba716"> <profile name="alternate" id="2" uuid="2ed07c19-2071-4d66-8569-da40475ba716">
<meta> <meta>
<names> <names>
<name>AnotherCD</name> <name>AnotherCD</name>
<uxname>bdisk_alt</uxname> <uxname>bdisk_alt</uxname>
<pname>{xpath_ref%../name/text()}</pname> <pname>{xpath%../name/text()}</pname>
</names> </names>
<desc>Another rescue/restore live environment.</desc> <desc>Another rescue/restore live environment.</desc>
<dev> <dev>
<author>Another Dev Eloper</author> <author>Another Dev Eloper</author>
<email>{xpath_ref%//profile[@name="default"]/meta/dev/email/text()}</email> <email>{xpath%//profile[@name="default"]/meta/dev/email/text()}</email>
<website>{xpath_ref%//profile[@name="default"]/meta/dev/website/text()}</website> <website>{xpath%//profile[@name="default"]/meta/dev/website/text()}</website>
</dev> </dev>
<uri>https://domain.tld/projname</uri> <uri>https://domain.tld/projname</uri>
<ver>0.0.1</ver> <ver>0.0.1</ver>
@ -154,79 +155,79 @@
<source arch="x86_64"> <source arch="x86_64">
<mirror>http://archlinux.mirror.domain.tld</mirror> <mirror>http://archlinux.mirror.domain.tld</mirror>
<webroot>/iso/latest</webroot> <webroot>/iso/latest</webroot>
<tarball flags="latest">{xpath_ref%../mirror/text()}{xpath_ref%../webroot/text()}/{regex%archlinux-bootstrap-[0-9]{4}\.[0-9]{2}\.[0-9]{2}-x86_64\.tar\.gz}</tarball> <tarball flags="regex,latest">{xpath%../mirror/text()}{xpath%../webroot/text()}/{regex%archlinux-bootstrap-[0-9]{4}\.[0-9]{2}\.[0-9]{2}-x86_64\.tar\.gz}</tarball>
<checksum hash_algo="sha1" flags="none">{xpath_ref%../mirror/text()}{xpath_ref%../webroot/text()}/sha1sums.txt</checksum> <checksum hash_algo="sha1" flags="none">{xpath%../mirror/text()}{xpath%../webroot/text()}/sha1sums.txt</checksum>
<sig keys="7F2D434B9741E8AC" keyserver="hkp://pool.sks-keyservers.net" flags="latest">{xpath_ref%../tarball/text()}.sig</sig> <sig keys="7F2D434B9741E8AC" keyserver="hkp://pool.sks-keyservers.net" flags="latest">{xpath%../tarball/text()}.sig</sig>
</source> </source>
<source arch="i686"> <source arch="i686">
<mirror>http://archlinux32.mirror.domain.tld</mirror> <mirror>http://archlinux32.mirror.domain.tld</mirror>
<webroot>/iso/latest</webroot> <webroot>/iso/latest</webroot>
<tarball flag="regex,latest">{xpath_ref%../mirror/text()}/{xpath_ref%../webroot/text()}/{regex%archlinux-bootstrap-[0-9]{4}\.[0-9]{2}\.[0-9]{2}-i686\.tar\.gz}</tarball> <tarball flag="regex,latest">{xpath%../mirror/text()}/{xpath%../webroot/text()}/{regex%archlinux-bootstrap-[0-9]{4}\.[0-9]{2}\.[0-9]{2}-i686\.tar\.gz}</tarball>
<checksum hash_algo="sha512" explicit="yes">cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e</checksum> <checksum hash_algo="sha512" explicit="yes">cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e</checksum>
<sig keys="248BF41F9BDD61D41D060AE774EDA3C6B06D0506" keyserver="hkp://pool.sks-keyservers.net">{xpath_ref%../tarball/text()}.sig</sig> <sig keys="248BF41F9BDD61D41D060AE774EDA3C6B06D0506" keyserver="hkp://pool.sks-keyservers.net">{xpath%../tarball/text()}.sig</sig>
</source> </source>
</sources> </sources>
<build its_full_of_stars="yes"> <build its_full_of_stars="yes">
<paths> <paths>
<cache>/var/tmp/{xpath_ref%//meta/names/uxname/text()}</cache> <cache>/var/tmp/{xpath%//meta/names/uxname/text()}</cache>
<chroot>/var/tmp/chroots/{xpath_ref%//meta/names/uxname/text()}</chroot> <chroot>/var/tmp/chroots/{xpath%//meta/names/uxname/text()}</chroot>
<overlay>{xpath_ref%../cache/text()}/overlay</overlay> <overlay>{xpath%../cache/text()}/overlay</overlay>
<templates>~/{xpath_ref%//meta/names/uxname/text()}/templates</templates> <templates>~/{xpath%//meta/names/uxname/text()}/templates</templates>
<mount>/mnt/{xpath_ref%//meta/names/uxname/text()}</mount> <mount>/mnt/{xpath%//meta/names/uxname/text()}</mount>
<distros>~/{xpath_ref%//meta/names/uxname/text()}/distros</distros> <distros>~/{xpath%//meta/names/uxname/text()}/distros</distros>
<dest>~/{xpath_ref%//meta/names/uxname/text()}/results</dest> <dest>~/{xpath%//meta/names/uxname/text()}/results</dest>
<iso>{xpath_ref%../dest/text()}/iso</iso> <iso>{xpath%../dest/text()}/iso</iso>
<http>{xpath_ref%../dest/text()}/http</http> <http>{xpath%../dest/text()}/http</http>
<tftp>{xpath_ref%../dest/text()}/tftp</tftp> <tftp>{xpath%../dest/text()}/tftp</tftp>
<ssl>{xpath_ref%../dest/text()}/pki</ssl> <pki>{xpath%../dest/text()}/pki</pki>
</paths> </paths>
<basedistro>archlinux</basedistro> <basedistro>archlinux</basedistro>
<iso sign="yes" sync="yes" multiarch="yes" rsync="yes"/>
<ipxe sign="yes" sync="yes" iso="yes" rsync="yes">
<ssl custom="no">
<ca>
<cert>{xpath_ref%//build/paths/ssl/text()}/ca.crt</cert>
<csr/>
<key des="no" passphrase="none">{xpath_ref%//build/paths/ssl/text()}/ca.key</key>
<subject>
<commonName>domain.tld</commonName>
<countryName>XX</countryName>
<localityName>Some City</localityName>
<stateOrProvinceName>Some State</stateOrProvinceName>
<organization>Some Org, Inc.</organization>
<organizationalUnitName>Department Name</organizationalUnitName>
<emailAddress>{xpath_ref%//meta/dev/email/text()}</emailAddress>
</subject>
</ca>
<server>
<cert>{xpath_ref%//build/paths/ssl/text()}/{xpath_ref%//meta/names/uxname/text()}.crt</cert>
<csr/>
<key des="no" passphrase="none">{xpath_ref%//build/paths/ssl/text()}/{xpath_ref%//meta/names/uxname/text()}.key</key>
<subject>
<commonName>domain.tld (client)</commonName>
<countryName>XX</countryName>
<localityName>Some City</localityName>
<stateOrProvinceName>Some State</stateOrProvinceName>
<organization>Some Org, Inc.</organization>
<organizationalUnitName>Department Name</organizationalUnitName>
<emailAddress>{xpath_ref%//meta/dev/email/text()}</emailAddress>
</subject>
</server>
</ssl>
<uri>{xpath_ref%//meta/dev/website/text()}/ipxe</uri>
</ipxe>
<gpg keyid="none" gnupghome="none" publish="no" sync="yes"/>
<sync>
<http enabled="yes" rsync="yes"/>
<tftp enabled="yes" rsync="yes"/>
<rsync enabled="yes">
<user>root</user>
<path>/srv/http/{xpath_ref%//meta/names/uxname/text()}</path>
<host>mirror.domain.tld</host>
<port>22</port>
<pubkey>~/.ssh/id_ed25519</pubkey>
</rsync>
</sync>
</build> </build>
<iso sign="yes" multiarch="yes"/>
<ipxe sign="yes" iso="yes">
<uri>{xpath%//meta/dev/website/text()}/ipxe</uri>
</ipxe>
<pki overwrite="no">
<ca>
<cert>{xpath%../../../build/paths/pki/text()}/ca.crt</cert>
<csr/>
<key des="no" passphrase="none">{xpath%../../../build/paths/pki/text()}/ca.key</key>
<subject>
<commonName>domain.tld</commonName>
<countryName>XX</countryName>
<localityName>Some City</localityName>
<stateOrProvinceName>Some State</stateOrProvinceName>
<organization>Some Org, Inc.</organization>
<organizationalUnitName>Department Name</organizationalUnitName>
<emailAddress>{xpath%../../../../meta/dev/email/text()}</emailAddress>
</subject>
</ca>
<client>
<cert>{xpath%../../../build/paths/pki/text()}/{xpath%../../../meta/names/uxname/text()}.crt</cert>
<csr/>
<key des="no" passphrase="none">{xpath%//build/paths/pki/text()}/{xpath%../../../meta/names/uxname/text()}.key</key>
<subject>
<commonName>some client name</commonName>
<countryName>XX</countryName>
<localityName>Some City</localityName>
<stateOrProvinceName>Some State</stateOrProvinceName>
<organization>Some Org, Inc.</organization>
<organizationalUnitName>Department Name</organizationalUnitName>
<emailAddress>{xpath%../../../../meta/dev/email/text()}</emailAddress>
</subject>
</client>
</pki>
<gpg keyid="none" gnupghome="none" publish="no" sync="yes"/>
<sync>
<ipxe enabled="yes" rsync="yes">/srv/http/{xpath%../../meta/names/uxname/text()}</ipxe>
<tftp enabled="yes" rsync="yes">/tftproot/{xpath%../../meta/names/uxname/text()}</tftp>
<iso enabled="yes" rsync="yes">/srv/http/isos/{xpath%../../meta/names/uxname/text()}</iso>
<rsync enabled="yes">
<user>root</user>
<host>mirror.domain.tld</host>
<port>22</port>
<pubkey>~/.ssh/id_ed25519</pubkey>
</rsync>
</sync>
</profile> </profile>
</bdisk> </bdisk>

View File

@ -19,11 +19,11 @@ alt_profile.attrib['uuid'] = '2ed07c19-2071-4d66-8569-da40475ba716'


meta_tags = {'name': 'AnotherCD', meta_tags = {'name': 'AnotherCD',
'uxname': 'bdisk_alt', 'uxname': 'bdisk_alt',
'pname': '{xpath_ref%../name/text()}', 'pname': '{xpath%../name/text()}',
'desc': 'Another rescue/restore live environment.', 'desc': 'Another rescue/restore live environment.',
'author': 'Another Dev Eloper', 'author': 'Another Dev Eloper',
'email': '{xpath_ref%//profile[@name="default"]/meta/dev/email/text()}', 'email': '{xpath%//profile[@name="default"]/meta/dev/email/text()}',
'website': '{xpath_ref%//profile[@name="default"]/meta/dev/website/text()}', 'website': '{xpath%//profile[@name="default"]/meta/dev/website/text()}',
'ver': '0.0.1'} 'ver': '0.0.1'}
# Change the names # Change the names
meta = alt_profile.xpath('/profile/meta')[0] meta = alt_profile.xpath('/profile/meta')[0]

View File

@ -8,8 +8,9 @@
<!-- Just like with previous versions of BDisk, you can reference other values... <!-- Just like with previous versions of BDisk, you can reference other values...
but now with the neat benefits of XPath! Everything you could do in build.ini's and more. but now with the neat benefits of XPath! Everything you could do in build.ini's and more.
See https://www.w3schools.com/xml/xpath_syntax.asp See https://www.w3schools.com/xml/xpath_syntax.asp
If you need a literal bracket, double them (e.g. for "{foo}", use "{{foo}}") --> If you need a literal curly brace, double them (e.g. for "{foo}", use "{{foo}}"),
<pname>{xpath_ref%../name/text()}</pname> UNLESS it's in a {regex%...} placeholder/filter (as part of the expression). -->
<pname>{xpath%../name/text()}</pname>
</names> </names>
<desc>A rescue/restore live environment.</desc> <desc>A rescue/restore live environment.</desc>
<dev> <dev>
@ -19,7 +20,7 @@
</dev> </dev>
<uri>https://domain.tld/projname</uri> <uri>https://domain.tld/projname</uri>
<ver>1.0.0</ver> <ver>1.0.0</ver>
<!-- This is the VERY FIRST value parsed, and is required. It controls how many levels of {xpath_ref%...} to recurse. --> <!-- This is the VERY FIRST value parsed, and is required. It controls how many levels of {xpath%...} to recurse. -->
<!-- If the maximum level is reached, the substitution will evaluate as blank. --> <!-- If the maximum level is reached, the substitution will evaluate as blank. -->
<max_recurse>5</max_recurse> <max_recurse>5</max_recurse>
</meta> </meta>
@ -27,10 +28,10 @@
<!-- Salted/hashed password is "test" --> <!-- Salted/hashed password is "test" -->
<rootpass hashed="yes">$6$7KfIdtHTcXwVrZAC$LZGNeMNz7v5o/cYuA48FAxtZynpIwO5B1CPGXnOW5kCTVpXVt4SypRqfM.AoKkFt/O7MZZ8ySXJmxpELKmdlF1</rootpass> <rootpass hashed="yes">$6$7KfIdtHTcXwVrZAC$LZGNeMNz7v5o/cYuA48FAxtZynpIwO5B1CPGXnOW5kCTVpXVt4SypRqfM.AoKkFt/O7MZZ8ySXJmxpELKmdlF1</rootpass>
<user sudo="yes"> <user sudo="yes">
<username>{xpath_ref%//meta/names/uxname/text()}</username> <username>{xpath%//meta/names/uxname/text()}</username>
<!-- You can also use substitution from different profiles: --> <!-- You can also use substitution from different profiles: -->
<!-- <username>{xpath_ref%//profile[@name='another_profile']/meta/names/uxname"}</username> --> <!-- <username>{xpath%//profile[@name='another_profile']/meta/names/uxname"}</username> -->
<comment>{xpath_ref%//meta/dev/author/text()}</comment> <comment>{xpath%//meta/dev/author/text()}</comment>
<password hashed="no" <password hashed="no"
hash_algo="sha512" hash_algo="sha512"
salt="auto">testpassword</password> salt="auto">testpassword</password>
@ -47,89 +48,89 @@
<source arch="x86_64"> <source arch="x86_64">
<mirror>http://archlinux.mirror.domain.tld</mirror> <mirror>http://archlinux.mirror.domain.tld</mirror>
<webroot>/iso/latest</webroot> <webroot>/iso/latest</webroot>
<tarball flags="latest">{xpath_ref%../mirror/text()}{xpath_ref%../webroot/text()}/{regex%archlinux-bootstrap-[0-9]{4}\.[0-9]{2}\.[0-9]{2}-x86_64\.tar\.gz}</tarball> <tarball flags="regex,latest">{xpath%../mirror/text()}{xpath%../webroot/text()}/{regex%archlinux-bootstrap-[0-9]{4}\.[0-9]{2}\.[0-9]{2}-x86_64\.tar\.gz}</tarball>
<checksum hash_algo="sha1" flags="none" >{xpath_ref%../mirror/text()}{xpath_ref%../webroot/text()}/sha1sums.txt</checksum> <checksum hash_algo="sha1" flags="none" >{xpath%../mirror/text()}{xpath%../webroot/text()}/sha1sums.txt</checksum>
<sig keys="7F2D434B9741E8AC" <sig keys="7F2D434B9741E8AC"
keyserver="hkp://pool.sks-keyservers.net" keyserver="hkp://pool.sks-keyservers.net"
flags="latest">{xpath_ref%../tarball/text()}.sig</sig> flags="latest">{xpath%../tarball/text()}.sig</sig>
</source> </source>
<source arch="i686"> <source arch="i686">
<mirror>http://archlinux32.mirror.domain.tld</mirror> <mirror>http://archlinux32.mirror.domain.tld</mirror>
<webroot>/iso/latest</webroot> <webroot>/iso/latest</webroot>
<tarball flag="regex,latest">{xpath_ref%../mirror/text()}/{xpath_ref%../webroot/text()}/{regex%archlinux-bootstrap-[0-9]{4}\.[0-9]{2}\.[0-9]{2}-i686\.tar\.gz}</tarball> <tarball flag="regex,latest">{xpath%../mirror/text()}/{xpath%../webroot/text()}/{regex%archlinux-bootstrap-[0-9]{4}\.[0-9]{2}\.[0-9]{2}-i686\.tar\.gz}</tarball>
<checksum hash_algo="sha512" explicit="yes">cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e</checksum> <checksum hash_algo="sha512" explicit="yes">cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e</checksum>
<sig keys="248BF41F9BDD61D41D060AE774EDA3C6B06D0506" <sig keys="248BF41F9BDD61D41D060AE774EDA3C6B06D0506"
keyserver="hkp://pool.sks-keyservers.net">{xpath_ref%../tarball/text()}.sig</sig> keyserver="hkp://pool.sks-keyservers.net">{xpath%../tarball/text()}.sig</sig>
</source> </source>
</sources> </sources>
<build its_full_of_stars="yes"> <build its_full_of_stars="yes">
<paths> <paths>
<cache>/var/tmp/{xpath_ref%//meta/names/uxname/text()}</cache> <cache>/var/tmp/{xpath%//meta/names/uxname/text()}</cache>
<chroot>/var/tmp/chroots/{xpath_ref%//meta/names/uxname/text()}</chroot> <chroot>/var/tmp/chroots/{xpath%//meta/names/uxname/text()}</chroot>
<overlay>{xpath_ref%../cache/text()}/overlay</overlay> <overlay>{xpath%../cache/text()}/overlay</overlay>
<templates>~/{xpath_ref%//meta/names/uxname/text()}/templates</templates> <templates>~/{xpath%//meta/names/uxname/text()}/templates</templates>
<mount>/mnt/{xpath_ref%//meta/names/uxname/text()}</mount> <mount>/mnt/{xpath%//meta/names/uxname/text()}</mount>
<distros>~/{xpath_ref%//meta/names/uxname/text()}/distros</distros> <distros>~/{xpath%//meta/names/uxname/text()}/distros</distros>
<dest>~/{xpath_ref%//meta/names/uxname/text()}/results</dest> <dest>~/{xpath%//meta/names/uxname/text()}/results</dest>
<iso>{xpath_ref%../dest/text()}/iso</iso> <iso>{xpath%../dest/text()}/iso</iso>
<http>{xpath_ref%../dest/text()}/http</http> <http>{xpath%../dest/text()}/http</http>
<tftp>{xpath_ref%../dest/text()}/tftp</tftp> <tftp>{xpath%../dest/text()}/tftp</tftp>
<ssl>{xpath_ref%../dest/text()}/pki</ssl> <pki>{xpath%../dest/text()}/pki</pki>
</paths> </paths>
<basedistro>archlinux</basedistro> <basedistro>archlinux</basedistro>
<iso sign="yes" sync="yes" multiarch="yes" rsync="yes"/>
<ipxe sign="yes" sync="yes" iso="yes" rsync="yes">
<ssl custom="no">
<!-- http://ipxe.org/crypto -->
<ca>
<cert>{xpath_ref%//build/paths/ssl/text()}/ca.crt</cert>
<!-- If csr is self-enclosed (<csr />), we'll just generate and use a CSR in-memory.
Assuming we need to generate a certificate, anyways.
If you want to write it out to disk (for debugging, etc.) OR use one already generated,
then provide a path.
e.g.:
<csr>{xpath_ref%build/paths/ssl/text()}/ca.csr</csr> -->
<csr />
<key des="no" passphrase="none">{xpath_ref%//build/paths/ssl/text()}/ca.key</key>
<subject>
<commonName>domain.tld</commonName>
<countryName>XX</countryName>
<localityName>Some City</localityName>
<stateOrProvinceName>Some State</stateOrProvinceName>
<organization>Some Org, Inc.</organization>
<organizationalUnitName>Department Name</organizationalUnitName>
<emailAddress>{xpath_ref%//meta/dev/email/text()}</emailAddress>
</subject>
</ca>
<server>
<cert>{xpath_ref%//build/paths/ssl/text()}/{xpath_ref%//meta/names/uxname/text()}.crt</cert>
<csr />
<key des="no" passphrase="none">{xpath_ref%//build/paths/ssl/text()}/{xpath_ref%//meta/names/uxname/text()}.key</key>
<subject>
<commonName>domain.tld (client)</commonName>
<countryName>XX</countryName>
<localityName>Some City</localityName>
<stateOrProvinceName>Some State</stateOrProvinceName>
<organization>Some Org, Inc.</organization>
<organizationalUnitName>Department Name</organizationalUnitName>
<emailAddress>{xpath_ref%//meta/dev/email/text()}</emailAddress>
</subject>
</server>
</ssl>
<uri>{xpath_ref%//meta/dev/website/text()}/ipxe</uri>
</ipxe>
<gpg keyid="none" gnupghome="none" publish="no" sync="yes" />
<sync>
<http enabled="yes" rsync="yes" />
<tftp enabled="yes" rsync="yes" />
<rsync enabled="yes">
<user>root</user>
<path>/srv/http/{xpath_ref%//meta/names/uxname/text()}</path>
<host>mirror.domain.tld</host>
<port>22</port>
<pubkey>~/.ssh/id_ed25519</pubkey>
</rsync>
</sync>
</build> </build>
<iso sign="yes" multiarch="yes" />
<ipxe sign="yes" iso="yes">
<uri>{xpath%//meta/dev/website/text()}/ipxe</uri>
</ipxe>
<pki overwrite="no">
<!-- http://ipxe.org/crypto -->
<ca>
<cert>{xpath%../../../build/paths/pki/text()}/ca.crt</cert>
<!-- If csr is self-enclosed (<csr />), we'll just generate and use a CSR in-memory.
Assuming we need to generate a certificate, anyways.
If you want to write it out to disk (for debugging, etc.) OR use one already generated,
then provide a path.
e.g.:
<csr>{xpath%build/paths/ssl/text()}/ca.csr</csr> -->
<csr />
<key des="no" passphrase="none">{xpath%../../../build/paths/pki/text()}/ca.key</key>
<subject>
<commonName>domain.tld</commonName>
<countryName>XX</countryName>
<localityName>Some City</localityName>
<stateOrProvinceName>Some State</stateOrProvinceName>
<organization>Some Org, Inc.</organization>
<organizationalUnitName>Department Name</organizationalUnitName>
<emailAddress>{xpath%../../../../meta/dev/email/text()}</emailAddress>
</subject>
</ca>
<client>
<cert>{xpath%../../../build/paths/pki/text()}/{xpath%../../../meta/names/uxname/text()}.crt</cert>
<csr />
<key des="no" passphrase="none">{xpath%//build/paths/pki/text()}/{xpath%../../../meta/names/uxname/text()}.key</key>
<subject>
<commonName>some client name</commonName>
<countryName>XX</countryName>
<localityName>Some City</localityName>
<stateOrProvinceName>Some State</stateOrProvinceName>
<organization>Some Org, Inc.</organization>
<organizationalUnitName>Department Name</organizationalUnitName>
<emailAddress>{xpath%../../../../meta/dev/email/text()}</emailAddress>
</subject>
</client>
</pki>
<gpg keyid="none" gnupghome="none" publish="no" sync="yes" />
<sync>
<ipxe enabled="yes" rsync="yes">/srv/http/{xpath%../../meta/names/uxname/text()}</ipxe>
<tftp enabled="yes" rsync="yes">/tftproot/{xpath%../../meta/names/uxname/text()}</tftp>
<iso enabled="yes" rsync="yes">/srv/http/isos/{xpath%../../meta/names/uxname/text()}</iso>
<rsync enabled="yes">
<user>root</user>
<host>mirror.domain.tld</host>
<port>22</port>
<pubkey>~/.ssh/id_ed25519</pubkey>
</rsync>
</sync>
</profile> </profile>
</bdisk> </bdisk>