beginnings of a conf generator
This commit is contained in:
parent
479c6e65bc
commit
bbb37c3c29
177
aif-config.py
Executable file
177
aif-config.py
Executable file
@ -0,0 +1,177 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
try:
|
||||
from lxml import etree
|
||||
lxml_avail = True
|
||||
except ImportError:
|
||||
import xml.etree.ElementTree as etree # https://docs.python.org/3/library/xml.etree.elementtree.html
|
||||
lxml_avail = False
|
||||
import argparse
|
||||
import datetime
|
||||
import errno
|
||||
import ipaddress
|
||||
import os
|
||||
import pydoc # a dirty hack we use for pagination
|
||||
import re
|
||||
import shlex
|
||||
import socket
|
||||
import sys
|
||||
import urllib.request as urlrequest
|
||||
import urllib.parse as urlparse
|
||||
import urllib.response as urlresponse
|
||||
from ftplib import FTP_TLS
|
||||
|
||||
xsd = 'https://aif.square-r00t.net/aif.xsd'
|
||||
|
||||
class aifgen(object):
|
||||
def __init__(self, args):
|
||||
self.args = args
|
||||
|
||||
def getXSD(self):
|
||||
pass
|
||||
|
||||
def getXML(self):
|
||||
pass
|
||||
|
||||
def getOpts(self):
|
||||
def chkPrompt(prompt, urls):
|
||||
txtin = None
|
||||
txtin = input(prompt)
|
||||
if txtin in ('wikihelp', ''):
|
||||
print('\n Articles/pages that you may find helpful for this option are:')
|
||||
for h in urls:
|
||||
print(' * {0}'.format(h))
|
||||
print()
|
||||
txtin = input(prompt)
|
||||
else:
|
||||
return(txtin)
|
||||
|
||||
conf = {}
|
||||
print('[{0}] Beginning configuration...'.format(datetime.datetime.now()))
|
||||
print('You may reply with \'wikihelp\' for the relevant link(s) in the Arch wiki ' +
|
||||
'(and other resources).\n')
|
||||
# https://aif.square-r00t.net/#code_disk_code
|
||||
diskhelp = ['https://wiki.archlinux.org/index.php/installation_guide#Partition_the_disks']
|
||||
diskin = chkPrompt('\nWhat disk(s) would you like to be configured on the target system?\n' +
|
||||
'If you have multiple disks, separate with a comma (e.g. \'/dev/sda,/dev/sdb\').\n', diskhelp)
|
||||
conf['disks'] = {}
|
||||
for d in diskin.split(','):
|
||||
disk = d.strip()
|
||||
if not re.match('^/dev/[A-Za-z0]+', disk):
|
||||
exit('!! ERROR: Disk {0} does not seem to be a valid device path.'.format(disk))
|
||||
conf['disks'][disk] = {}
|
||||
print('\nConfiguring disk {0} ...'.format(disk))
|
||||
fmtin = chkPrompt('* What format should this disk use (gpt/bios)? ', diskhelp)
|
||||
fmt = fmtin.lower()
|
||||
if fmt not in ('gpt', 'bios'):
|
||||
exit(' !! ERROR: Must be one of \'gpt\' or \'bios\'.')
|
||||
conf['disks'][disk]['fmt'] = fmt
|
||||
if fmt == 'gpt':
|
||||
maxpart = '256'
|
||||
else:
|
||||
maxpart = '4'
|
||||
partnumsin = chkPrompt('* How many partitions should this disk have? (Maximum: {0}) '.format(maxpart), diskhelp)
|
||||
if not isinstance(partnumsin, int):
|
||||
exit(' !! ERROR: Must be an integer.')
|
||||
if partnumsin < 1:
|
||||
exit(' !! ERROR: Must be a positive integer.')
|
||||
if partnumsin > int(maxpart):
|
||||
exit(' !! ERROR: Must be less than {0}'.format(maxpart))
|
||||
parthelp = diskhelp + ['https://wiki.archlinux.org/index.php/installation_guide#Format_the_partitions',
|
||||
'https://aif.square-r00t.net/#code_part_code',
|
||||
'https://aif.square-r00t.net/#fstypes']
|
||||
for partn in range(1, partnumsin + 1):
|
||||
startsize = chkPrompt(('** Where should partition {0} start? Can be percentage [n%] ' +
|
||||
'or size [(+/-)n(K/M/G/T/P)]: ').format(partn), parthelp)
|
||||
startn = re.sub('[%\-+KMGTP])', '', startsize)
|
||||
if int(startn) not in range(0, 100):
|
||||
exit()
|
||||
# https://aif.square-r00t.net/#code_part_code
|
||||
parthelp.append('https://aif.square-r00t.net/#code_part_code')
|
||||
|
||||
def validateXML(self):
|
||||
pass
|
||||
|
||||
def main(self):
|
||||
if self.args['oper'] == 'create':
|
||||
self.getOpts()
|
||||
if self.args['oper'] in ('create', 'view'):
|
||||
self.validateXML()
|
||||
|
||||
def parseArgs():
|
||||
args = argparse.ArgumentParser(description = 'AIF-NG Configuration Generator',
|
||||
epilog = 'TIP: this program has context-specific help. e.g. try "%(prog)s create --help"')
|
||||
commonargs = argparse.ArgumentParser(add_help = False)
|
||||
commonargs.add_argument('-f',
|
||||
'--file',
|
||||
dest = 'cfgfile',
|
||||
help = 'The file to create/validate/view. If not specified, defaults to ./aif.xml',
|
||||
default = '{0}/aif.xml'.format(os.getcwd()))
|
||||
subparsers = args.add_subparsers(help = 'Operation to perform',
|
||||
dest = 'oper')
|
||||
createargs = subparsers.add_parser('create',
|
||||
help = 'Create an AIF-NG XML configuration file.',
|
||||
parents = [commonargs])
|
||||
validateargs = subparsers.add_parser('validate',
|
||||
help = 'Validate an AIF-NG XML configuration file.',
|
||||
parents = [commonargs])
|
||||
viewargs = subparsers.add_parser('view',
|
||||
help = 'View an AIF-NG XML configuration file.',
|
||||
parents = [commonargs])
|
||||
|
||||
return(args)
|
||||
|
||||
def verifyArgs(args):
|
||||
args['cfgfile'] = os.path.normpath(os.path.abspath(os.path.expanduser(args['cfgfile'])))
|
||||
args['cfgfile'] = re.sub('^/+', '/', args['cfgfile'])
|
||||
# Path/file handling - make sure we can create the parent dir if it doesn't exist,
|
||||
# check that we can write to the file, etc.
|
||||
if args['oper'] == 'create':
|
||||
args['cfgbak'] = '{0}.bak.{1}'.format(args['cfgfile'], int(datetime.datetime.utcnow().timestamp()))
|
||||
try:
|
||||
temp = True
|
||||
#mtime = None
|
||||
#atime = None
|
||||
if os.path.lexists(args['cfgfile']):
|
||||
temp = False
|
||||
#mtime = os.stat(args['cfgfile']).st_mtime
|
||||
#atime = os.stat(args['cfgfile']).st_atime
|
||||
os.makedirs(os.path.dirname(args['cfgfile']), exist_ok = True)
|
||||
with open(args['cfgfile'], 'a') as f:
|
||||
f.write('')
|
||||
if temp:
|
||||
os.remove(args['cfgfile'])
|
||||
#else:
|
||||
# WE WERE NEVER HERE.
|
||||
# I lied; ctime will still be modified, but I think this is playing it safely enough.
|
||||
# Turns out, though, f.write('') does no modifications but WILL throw the perm error we want.
|
||||
# Good.
|
||||
#os.utime(args['cfgfile'], times = (atime, mtime))
|
||||
except OSError as e:
|
||||
print('\nERROR: {0}: {1}'.format(e.strerror, e.filename))
|
||||
exit(('\nWe encountered an error when trying to use path {0}.\n' +
|
||||
'Please review the output and address any issues present.').format(args['cfgfile']))
|
||||
elif args['oper'] == 'view':
|
||||
try:
|
||||
with open(args['cfgfile'], 'r') as f:
|
||||
f.read()
|
||||
except OSError as e:
|
||||
print('\nERROR: {0}: {1}'.format(e.strerror, e.filename))
|
||||
exit(('\nWe encountered an error when trying to use path {0}.\n' +
|
||||
'Please review the output and address any issues present.').format(args['cfgfile']))
|
||||
return(args)
|
||||
|
||||
def main():
|
||||
args = vars(parseArgs().parse_args())
|
||||
if not args['oper']:
|
||||
parseArgs().print_help()
|
||||
else:
|
||||
# verifyArgs(args)
|
||||
aif = aifgen(verifyArgs(args))
|
||||
if args['oper'] == 'create':
|
||||
aif.getOpts()
|
||||
import pprint # DEBUGGING
|
||||
print(args) # DEBUGGING
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
Loading…
Reference in New Issue
Block a user