mirror of
https://github.com/kevingruesser/bootstrap-vz.git
synced 2025-08-22 09:50:37 +00:00
Convert param docs into parseable format.
This commit is contained in:
parent
ee6df57f3f
commit
ee3fe0bf42
24 changed files with 168 additions and 240 deletions
|
@ -7,10 +7,9 @@ from main import main
|
|||
def validate_manifest(data, validator, error):
|
||||
"""Validates the manifest using the base manifest
|
||||
|
||||
Args:
|
||||
data (dict): The data of the manifest
|
||||
validator (function): The function that validates the manifest given the data and a path
|
||||
error (function): The function tha raises an error when the validation fails
|
||||
:param dict data: The data of the manifest
|
||||
:param function validator: The function that validates the manifest given the data and a path
|
||||
:param function error: The function tha raises an error when the validation fails
|
||||
"""
|
||||
import os.path
|
||||
schema_path = os.path.normpath(os.path.join(os.path.dirname(__file__), 'manifest-schema.json'))
|
||||
|
|
|
@ -9,9 +9,8 @@ class BootstrapInformation(object):
|
|||
def __init__(self, manifest=None, debug=False):
|
||||
"""Instantiates a new bootstrap info object.
|
||||
|
||||
Args:
|
||||
manifest (Manifest): The manifest
|
||||
debug (bool): Whether debugging is turned on
|
||||
:param Manifest manifest: The manifest
|
||||
:param bool debug: Whether debugging is turned on
|
||||
"""
|
||||
# Set the manifest attribute.
|
||||
self.manifest = manifest
|
||||
|
@ -74,6 +73,14 @@ class BootstrapInformation(object):
|
|||
setattr(self, '_' + pluginname, {})
|
||||
|
||||
def __create_manifest_vars(self, manifest, additional_vars={}):
|
||||
"""Creates the manifest variables dictionary, based on the manifest contents
|
||||
and additional data.
|
||||
|
||||
:param Manifest manifest: The Manifest
|
||||
:param dict additional_vars: Additional values (they will take precedence and overwrite anything else)
|
||||
:return: The manifest_vars dictionary
|
||||
:rtype: dict
|
||||
"""
|
||||
class DictClass(dict):
|
||||
"""Tiny extension of dict to allow setting and getting keys via attributes
|
||||
"""
|
||||
|
@ -89,9 +96,8 @@ class BootstrapInformation(object):
|
|||
def set_manifest_vars(obj, data):
|
||||
"""Runs through the manifest and creates DictClasses for every key
|
||||
|
||||
Args:
|
||||
obj (dict): dictionary to set the values on
|
||||
data (dict): dictionary of values to set on the obj
|
||||
:param dict obj: dictionary to set the values on
|
||||
:param dict data: dictionary of values to set on the obj
|
||||
"""
|
||||
for key, value in data.iteritems():
|
||||
if isinstance(value, dict):
|
||||
|
|
|
@ -2,12 +2,12 @@
|
|||
|
||||
def load_volume(data, bootloader):
|
||||
"""Instantiates a volume that corresponds to the data in the manifest
|
||||
Args:
|
||||
data (dict): The 'volume' section from the manifest
|
||||
bootloader (str): Name of the bootloader the system will boot with
|
||||
|
||||
Returns:
|
||||
Volume. The volume that represents all information pertaining to the volume we bootstrap on
|
||||
:param dict data: The 'volume' section from the manifest
|
||||
:param str bootloader: Name of the bootloader the system will boot with
|
||||
|
||||
:return: The volume that represents all information pertaining to the volume we bootstrap on.
|
||||
:rtype: Volume
|
||||
"""
|
||||
# Create a mapping between valid partition maps in the manifest and their corresponding classes
|
||||
from partitionmaps.gpt import GPTPartitionMap
|
||||
|
|
|
@ -20,8 +20,7 @@ class AbstractPartitionMap(FSMProxy):
|
|||
|
||||
def __init__(self, bootloader):
|
||||
"""
|
||||
Args:
|
||||
bootloader (str): Name of the bootloader we will use for bootstrapping
|
||||
:param str bootloader: Name of the bootloader we will use for bootstrapping
|
||||
"""
|
||||
# Create the configuration for the state machine
|
||||
cfg = {'initial': 'nonexistent', 'events': self.events, 'callbacks': {}}
|
||||
|
@ -30,16 +29,15 @@ class AbstractPartitionMap(FSMProxy):
|
|||
def is_blocking(self):
|
||||
"""Returns whether the partition map is blocking volume detach operations
|
||||
|
||||
Returns:
|
||||
bool.
|
||||
:rtype: bool
|
||||
"""
|
||||
return self.fsm.current == 'mapped'
|
||||
|
||||
def get_total_size(self):
|
||||
"""Returns the total size the partitions occupy
|
||||
|
||||
Returns:
|
||||
Bytes. The size of all the partitions
|
||||
:return: The size of all partitions
|
||||
:rtype: Bytes
|
||||
"""
|
||||
# We just need the endpoint of the last partition
|
||||
return self.partitions[-1].get_end()
|
||||
|
@ -47,8 +45,7 @@ class AbstractPartitionMap(FSMProxy):
|
|||
def create(self, volume):
|
||||
"""Creates the partition map
|
||||
|
||||
Args:
|
||||
volume (Volume): The volume to create the partition map on
|
||||
:param Volume volume: The volume to create the partition map on
|
||||
"""
|
||||
self.fsm.create(volume=volume)
|
||||
|
||||
|
@ -59,15 +56,13 @@ class AbstractPartitionMap(FSMProxy):
|
|||
def map(self, volume):
|
||||
"""Maps the partition map to device nodes
|
||||
|
||||
Args:
|
||||
volume (Volume): The volume the partition map resides on
|
||||
:param Volume volume: The volume the partition map resides on
|
||||
"""
|
||||
self.fsm.map(volume=volume)
|
||||
|
||||
def _before_map(self, event):
|
||||
"""
|
||||
Raises:
|
||||
PartitionError
|
||||
:raises PartitionError: In case a partition could not be mapped.
|
||||
"""
|
||||
volume = event.volume
|
||||
try:
|
||||
|
@ -105,15 +100,13 @@ class AbstractPartitionMap(FSMProxy):
|
|||
def unmap(self, volume):
|
||||
"""Unmaps the partition
|
||||
|
||||
Args:
|
||||
volume (Volume): The volume to unmap the partition map from
|
||||
:param Volume volume: The volume to unmap the partition map from
|
||||
"""
|
||||
self.fsm.unmap(volume=volume)
|
||||
|
||||
def _before_unmap(self, event):
|
||||
"""
|
||||
Raises:
|
||||
PartitionError
|
||||
:raises PartitionError: If the a partition cannot be unmapped
|
||||
"""
|
||||
volume = event.volume
|
||||
# Run through all partitions before unmapping and make sure they can all be unmapped
|
||||
|
|
|
@ -10,9 +10,8 @@ class GPTPartitionMap(AbstractPartitionMap):
|
|||
|
||||
def __init__(self, data, bootloader):
|
||||
"""
|
||||
Args:
|
||||
data (dict): volume.partitions part of the manifest
|
||||
bootloader (str): Name of the bootloader we will use for bootstrapping
|
||||
:param dict data: volume.partitions part of the manifest
|
||||
:param str bootloader: Name of the bootloader we will use for bootstrapping
|
||||
"""
|
||||
from bootstrapvz.common.bytes import Bytes
|
||||
# List of partitions
|
||||
|
|
|
@ -11,9 +11,8 @@ class MSDOSPartitionMap(AbstractPartitionMap):
|
|||
|
||||
def __init__(self, data, bootloader):
|
||||
"""
|
||||
Args:
|
||||
data (dict): volume.partitions part of the manifest
|
||||
bootloader (str): Name of the bootloader we will use for bootstrapping
|
||||
:param dict data: volume.partitions part of the manifest
|
||||
:param str bootloader: Name of the bootloader we will use for bootstrapping
|
||||
"""
|
||||
from bootstrapvz.common.bytes import Bytes
|
||||
# List of partitions
|
||||
|
|
|
@ -9,9 +9,8 @@ class NoPartitions(object):
|
|||
|
||||
def __init__(self, data, bootloader):
|
||||
"""
|
||||
Args:
|
||||
data (dict): volume.partitions part of the manifest
|
||||
bootloader (str): Name of the bootloader we will use for bootstrapping
|
||||
:param dict data: volume.partitions part of the manifest
|
||||
:param str bootloader: Name of the bootloader we will use for bootstrapping
|
||||
"""
|
||||
from bootstrapvz.common.bytes import Bytes
|
||||
# In the NoPartitions partitions map we only have a single 'partition'
|
||||
|
@ -22,15 +21,14 @@ class NoPartitions(object):
|
|||
def is_blocking(self):
|
||||
"""Returns whether the partition map is blocking volume detach operations
|
||||
|
||||
Returns:
|
||||
bool.
|
||||
:rtype: bool
|
||||
"""
|
||||
return self.root.fsm.current == 'mounted'
|
||||
|
||||
def get_total_size(self):
|
||||
"""Returns the total size the partitions occupy
|
||||
|
||||
Returns:
|
||||
Bytes. The size of all the partitions
|
||||
:return: The size of all the partitions
|
||||
:rtype: Bytes
|
||||
"""
|
||||
return self.root.get_end()
|
||||
|
|
|
@ -24,10 +24,9 @@ class AbstractPartition(FSMProxy):
|
|||
"""
|
||||
def __init__(self, source, destination, opts):
|
||||
"""
|
||||
Args:
|
||||
source (str,AbstractPartition): The path from where we mount or a partition
|
||||
destination (str): The path of the mountpoint
|
||||
opts (list): List of options to pass to the mount command
|
||||
:param str,AbstractPartition source: The path from where we mount or a partition
|
||||
:param str destination: The path of the mountpoint
|
||||
:param list opts: List of options to pass to the mount command
|
||||
"""
|
||||
self.source = source
|
||||
self.destination = destination
|
||||
|
@ -36,8 +35,7 @@ class AbstractPartition(FSMProxy):
|
|||
def mount(self, prefix):
|
||||
"""Performs the mount operation or forwards it to another partition
|
||||
|
||||
Args:
|
||||
prefix (str): Path prefix of the mountpoint
|
||||
:param str prefix: Path prefix of the mountpoint
|
||||
"""
|
||||
mount_dir = os.path.join(prefix, self.destination)
|
||||
# If the source is another partition, we tell that partition to mount itself
|
||||
|
@ -59,10 +57,9 @@ class AbstractPartition(FSMProxy):
|
|||
|
||||
def __init__(self, size, filesystem, format_command):
|
||||
"""
|
||||
Args:
|
||||
size (Bytes): Size of the partition
|
||||
filesystem (str): Filesystem the partition should be formatted with
|
||||
format_command (list): Optional format command, valid variables are fs, device_path and size
|
||||
:param Bytes size: Size of the partition
|
||||
:param str filesystem: Filesystem the partition should be formatted with
|
||||
:param list format_command: Optional format command, valid variables are fs, device_path and size
|
||||
"""
|
||||
self.size = size
|
||||
self.filesystem = filesystem
|
||||
|
@ -79,8 +76,8 @@ class AbstractPartition(FSMProxy):
|
|||
def get_uuid(self):
|
||||
"""Gets the UUID of the partition
|
||||
|
||||
Returns:
|
||||
str. The UUID of the partition
|
||||
:return: The UUID of the partition
|
||||
:rtype: str
|
||||
"""
|
||||
[uuid] = log_check_call(['blkid', '-s', 'UUID', '-o', 'value', self.device_path])
|
||||
return uuid
|
||||
|
@ -92,8 +89,8 @@ class AbstractPartition(FSMProxy):
|
|||
def get_end(self):
|
||||
"""Gets the end of the partition
|
||||
|
||||
Returns:
|
||||
Bytes. The end of the partition
|
||||
:return: The end of the partition
|
||||
:rtype: Bytes
|
||||
"""
|
||||
return self.get_start() + self.size
|
||||
|
||||
|
@ -141,10 +138,9 @@ class AbstractPartition(FSMProxy):
|
|||
"""Associate a mount with this partition
|
||||
Automatically mounts it
|
||||
|
||||
Args:
|
||||
source (str,AbstractPartition): The source of the mount
|
||||
destination (str): The path to the mountpoint
|
||||
opts (list): Any options that should be passed to the mount command
|
||||
:param str,AbstractPartition source: The source of the mount
|
||||
:param str destination: The path to the mountpoint
|
||||
:param list opts: Any options that should be passed to the mount command
|
||||
"""
|
||||
# Create a new mount object, mount it if the partition is mounted and put it in the mounts dict
|
||||
mount = self.Mount(source, destination, opts)
|
||||
|
@ -156,8 +152,7 @@ class AbstractPartition(FSMProxy):
|
|||
"""Remove a mount from this partition
|
||||
Automatically unmounts it
|
||||
|
||||
Args:
|
||||
destination (str): The mountpoint path of the mount that should be removed
|
||||
:param str destination: The mountpoint path of the mount that should be removed
|
||||
"""
|
||||
# Unmount the mount if the partition is mounted and delete it from the mounts dict
|
||||
# If the mount is already unmounted and the source is a partition, this will raise an exception
|
||||
|
|
|
@ -20,11 +20,10 @@ class BasePartition(AbstractPartition):
|
|||
|
||||
def __init__(self, size, filesystem, format_command, previous):
|
||||
"""
|
||||
Args:
|
||||
size (Bytes): Size of the partition
|
||||
filesystem (str): Filesystem the partition should be formatted with
|
||||
format_command (list): Optional format command, valid variables are fs, device_path and size
|
||||
previous (BasePartition): The partition that preceeds this one
|
||||
:param Bytes size: Size of the partition
|
||||
:param str filesystem: Filesystem the partition should be formatted with
|
||||
:param list format_command: Optional format command, valid variables are fs, device_path and size
|
||||
:param BasePartition previous: The partition that preceeds this one
|
||||
"""
|
||||
# By saving the previous partition we have
|
||||
# a linked list that partitions can go backwards in to find the first partition.
|
||||
|
@ -39,16 +38,15 @@ class BasePartition(AbstractPartition):
|
|||
def create(self, volume):
|
||||
"""Creates the partition
|
||||
|
||||
Args:
|
||||
volume (Volume): The volume to create the partition on
|
||||
:param Volume volume: The volume to create the partition on
|
||||
"""
|
||||
self.fsm.create(volume=volume)
|
||||
|
||||
def get_index(self):
|
||||
"""Gets the index of this partition in the partition map
|
||||
|
||||
Returns:
|
||||
int. The index of the partition in the partition map
|
||||
:return: The index of the partition in the partition map
|
||||
:rtype: int
|
||||
"""
|
||||
if self.previous is None:
|
||||
# Partitions are 1 indexed
|
||||
|
@ -60,8 +58,8 @@ class BasePartition(AbstractPartition):
|
|||
def get_start(self):
|
||||
"""Gets the starting byte of this partition
|
||||
|
||||
Returns:
|
||||
Bytes. The starting byte of this partition
|
||||
:return: The starting byte of this partition
|
||||
:rtype: Bytes
|
||||
"""
|
||||
if self.previous is None:
|
||||
# If there is no previous partition, this partition begins at the offset
|
||||
|
@ -73,8 +71,7 @@ class BasePartition(AbstractPartition):
|
|||
def map(self, device_path):
|
||||
"""Maps the partition to a device_path
|
||||
|
||||
Args:
|
||||
device_path (str): The device patht his partition should be mapped to
|
||||
:param str device_path: The device patht his partition should be mapped to
|
||||
"""
|
||||
self.fsm.map(device_path=device_path)
|
||||
|
||||
|
|
|
@ -8,12 +8,11 @@ class GPTPartition(BasePartition):
|
|||
|
||||
def __init__(self, size, filesystem, format_command, name, previous):
|
||||
"""
|
||||
Args:
|
||||
size (Bytes): Size of the partition
|
||||
filesystem (str): Filesystem the partition should be formatted with
|
||||
format_command (list): Optional format command, valid variables are fs, device_path and size
|
||||
name (str): The name of the partition
|
||||
previous (BasePartition): The partition that preceeds this one
|
||||
:param Bytes size: Size of the partition
|
||||
:param str filesystem: Filesystem the partition should be formatted with
|
||||
:param list format_command: Optional format command, valid variables are fs, device_path and size
|
||||
:param str name: The name of the partition
|
||||
:param BasePartition previous: The partition that preceeds this one
|
||||
"""
|
||||
self.name = name
|
||||
super(GPTPartition, self).__init__(size, filesystem, format_command, previous)
|
||||
|
|
|
@ -8,9 +8,8 @@ class GPTSwapPartition(GPTPartition):
|
|||
|
||||
def __init__(self, size, previous):
|
||||
"""
|
||||
Args:
|
||||
size (Bytes): Size of the partition
|
||||
previous (BasePartition): The partition that preceeds this one
|
||||
:param Bytes size: Size of the partition
|
||||
:param BasePartition previous: The partition that preceeds this one
|
||||
"""
|
||||
super(GPTSwapPartition, self).__init__(size, 'swap', None, 'swap', previous)
|
||||
|
||||
|
|
|
@ -8,9 +8,8 @@ class MSDOSSwapPartition(MSDOSPartition):
|
|||
|
||||
def __init__(self, size, previous):
|
||||
"""
|
||||
Args:
|
||||
size (Bytes): Size of the partition
|
||||
previous (BasePartition): The partition that preceeds this one
|
||||
:param Bytes size: Size of the partition
|
||||
:param BasePartition previous: The partition that preceeds this one
|
||||
"""
|
||||
super(MSDOSSwapPartition, self).__init__(size, 'swap', None, previous)
|
||||
|
||||
|
|
|
@ -8,8 +8,8 @@ class SinglePartition(AbstractPartition):
|
|||
def get_start(self):
|
||||
"""Gets the starting byte of this partition
|
||||
|
||||
Returns:
|
||||
Bytes. The starting byte of this partition
|
||||
:return: The starting byte of this partition
|
||||
:rtype: Bytes
|
||||
"""
|
||||
from bootstrapvz.common.bytes import Bytes
|
||||
# On an unpartitioned volume there is no offset and no previous partition
|
||||
|
|
|
@ -14,8 +14,7 @@ class UnformattedPartition(BasePartition):
|
|||
|
||||
def __init__(self, size, previous):
|
||||
"""
|
||||
Args:
|
||||
size (Bytes): Size of the partition
|
||||
previous (BasePartition): The partition that preceeds this one
|
||||
:param Bytes size: Size of the partition
|
||||
:param BasePartition previous: The partition that preceeds this one
|
||||
"""
|
||||
super(UnformattedPartition, self).__init__(size, None, None, previous)
|
||||
|
|
|
@ -23,8 +23,7 @@ class Volume(FSMProxy):
|
|||
|
||||
def __init__(self, partition_map):
|
||||
"""
|
||||
Args:
|
||||
partition_map (PartitionMap): The partition map for the volume
|
||||
:param PartitionMap partition_map: The partition map for the volume
|
||||
"""
|
||||
# Path to the volume
|
||||
self.device_path = None
|
||||
|
@ -50,10 +49,6 @@ class Volume(FSMProxy):
|
|||
super(Volume, self).__init__(cfg)
|
||||
|
||||
def _after_create(self, e):
|
||||
"""
|
||||
Args:
|
||||
e (_e_obj): Event object containing arguments to create()
|
||||
"""
|
||||
if isinstance(self.partition_map, NoPartitions):
|
||||
# When the volume has no partitions, the virtual root partition
|
||||
# is essentially created when the volume is created, forward that creation event.
|
||||
|
@ -62,11 +57,7 @@ class Volume(FSMProxy):
|
|||
def _check_blocking(self, e):
|
||||
"""Checks whether the volume is blocked
|
||||
|
||||
Args:
|
||||
e (_e_obj): Event object containing arguments to create()
|
||||
|
||||
Raises:
|
||||
VolumeError
|
||||
:raises VolumeError: When the volume is blocked from being detached
|
||||
"""
|
||||
# Only the partition map can block the volume
|
||||
if self.partition_map.is_blocking():
|
||||
|
@ -78,16 +69,16 @@ class Volume(FSMProxy):
|
|||
Mainly it is used to fool grub into thinking that it is working with a real volume,
|
||||
rather than a loopback device or a network block device.
|
||||
|
||||
Args:
|
||||
e (_e_obj): Event object containing arguments to create()
|
||||
Arguments are:
|
||||
logical_start_sector (int): The sector the volume should start at in the new volume
|
||||
start_sector (int): The offset at which the volume should begin to be mapped in the new volume
|
||||
sectors (int): The number of sectors that should be mapped
|
||||
Read more at: http://manpages.debian.org/cgi-bin/man.cgi?query=dmsetup&apropos=0&sektion=0&manpath=Debian+7.0+wheezy&format=html&locale=en
|
||||
:param _e_obj e: Event object containing arguments to create()
|
||||
Keyword arguments to link_dm_node() are:
|
||||
|
||||
Raises:
|
||||
VolumeError
|
||||
:param int logical_start_sector: The sector the volume should start at in the new volume
|
||||
:param int start_sector: The offset at which the volume should begin to be mapped in the new volume
|
||||
:param int sectors: The number of sectors that should be mapped
|
||||
|
||||
Read more at: http://manpages.debian.org/cgi-bin/man.cgi?query=dmsetup&apropos=0&sektion=0&manpath=Debian+7.0+wheezy&format=html&locale=en
|
||||
|
||||
:raises VolumeError: When a free block device cannot be found.
|
||||
"""
|
||||
import os.path
|
||||
from bootstrapvz.common.fs import get_partitions
|
||||
|
@ -134,9 +125,6 @@ class Volume(FSMProxy):
|
|||
|
||||
def _before_unlink_dm_node(self, e):
|
||||
"""Unlinks the device mapping
|
||||
|
||||
Args:
|
||||
e (_e_obj): Event object containing arguments to create()
|
||||
"""
|
||||
log_check_call(['dmsetup', 'remove', self.dm_node_name])
|
||||
# Reset the device_path
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
"""This module holds functions and classes responsible for formatting the log output
|
||||
both to a file and to the console.
|
||||
.. module:: log
|
||||
"""
|
||||
import logging
|
||||
|
||||
|
@ -9,11 +8,9 @@ def get_log_filename(manifest_path):
|
|||
"""Returns the path to a logfile given a manifest
|
||||
The logfile name is constructed from the current timestamp and the basename of the manifest
|
||||
|
||||
Args:
|
||||
manifest_path (str): The path to the manifest
|
||||
|
||||
Returns:
|
||||
str. The path to the logfile
|
||||
:param str manifest_path: The path to the manifest
|
||||
:return: The path to the logfile
|
||||
:rtype: str
|
||||
"""
|
||||
import os.path
|
||||
from datetime import datetime
|
||||
|
@ -28,9 +25,8 @@ def get_log_filename(manifest_path):
|
|||
def setup_logger(logfile=None, debug=False):
|
||||
"""Sets up the python logger to log to both a file and the console
|
||||
|
||||
Args:
|
||||
logfile (str): Path to a logfile
|
||||
debug (bool): Whether to log debug output to the console
|
||||
:param str logfile: Path to a logfile
|
||||
:param bool debug: Whether to log debug output to the console
|
||||
"""
|
||||
root = logging.getLogger()
|
||||
# Make sure all logging statements are processed by our handlers, they decide the log level
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
"""Main module containing all the setup necessary for running the bootstrapping process
|
||||
.. module:: main
|
||||
"""
|
||||
|
||||
import logging
|
||||
|
@ -9,8 +8,7 @@ log = logging.getLogger(__name__)
|
|||
def main():
|
||||
"""Main function for invoking the bootstrap process
|
||||
|
||||
Raises:
|
||||
Exception
|
||||
:raises Exception: When the invoking user is not root and --dry-run isn't specified
|
||||
"""
|
||||
# Get the commandline arguments
|
||||
opts = get_opts()
|
||||
|
@ -58,8 +56,7 @@ Options:
|
|||
def run(opts):
|
||||
"""Runs the bootstrapping process
|
||||
|
||||
Args:
|
||||
opts (dict): Dictionary of options from the commandline
|
||||
:params dict opts: Dictionary of options from the commandline
|
||||
"""
|
||||
# Load the manifest
|
||||
from manifest import Manifest
|
||||
|
@ -97,9 +94,8 @@ def run(opts):
|
|||
"""counter_task() adds the second argument to the rollback tasklist
|
||||
if the first argument is present in the list of completed tasks
|
||||
|
||||
Args:
|
||||
task (Task): The task to look for in the completed tasks list
|
||||
counter (Task): The task to add to the rollback tasklist
|
||||
:param Task task: The task to look for in the completed tasks list
|
||||
:param Task counter: The task to add to the rollback tasklist
|
||||
"""
|
||||
if task in tasklist.tasks_completed and counter not in tasklist.tasks_completed:
|
||||
rollback_tasklist.tasks.add(counter)
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
"""The Manifest module contains the manifest that providers and plugins use
|
||||
to determine which tasks should be added to the tasklist, what arguments various
|
||||
invocations should have etc..
|
||||
.. module:: manifest
|
||||
"""
|
||||
from bootstrapvz.common.tools import load_json
|
||||
from bootstrapvz.common.tools import load_yaml
|
||||
|
@ -19,8 +18,7 @@ class Manifest(object):
|
|||
def __init__(self, path):
|
||||
"""Initializer: Given a path we load, validate and parse the manifest.
|
||||
|
||||
Args:
|
||||
path (str): The path to the manifest
|
||||
:param str path: The path to the manifest
|
||||
"""
|
||||
self.path = path
|
||||
self.load()
|
||||
|
@ -100,9 +98,8 @@ class Manifest(object):
|
|||
"""This convenience function is passed around to all the validation functions
|
||||
so that they may run a json-schema validation by giving it the data and a path to the schema.
|
||||
|
||||
Args:
|
||||
data (dict): Data to validate (normally the manifest data)
|
||||
schema_path (str): Path to the json-schema to use for validation
|
||||
:param dict data: Data to validate (normally the manifest data)
|
||||
:param str schema_path: Path to the json-schema to use for validation
|
||||
"""
|
||||
import jsonschema
|
||||
schema = load_json(schema_path)
|
||||
|
@ -115,9 +112,9 @@ class Manifest(object):
|
|||
"""This function is passed to all validation functions so that they may
|
||||
raise a validation error because a custom validation of the manifest failed.
|
||||
|
||||
Args:
|
||||
message (str): Message to user about the error
|
||||
json_path (list): A path to the location in the manifest where the error occurred
|
||||
:param str message: Message to user about the error
|
||||
:param list json_path: A path to the location in the manifest where the error occurred
|
||||
:raises ManifestError: With absolute certainty
|
||||
"""
|
||||
from bootstrapvz.common.exceptions import ManifestError
|
||||
raise ManifestError(message, self.path, json_path)
|
||||
|
|
|
@ -15,21 +15,21 @@ class Phase(object):
|
|||
def pos(self):
|
||||
"""Gets the position of the phase
|
||||
|
||||
Returns:
|
||||
int. The positional index of the phase in relation to the other phases
|
||||
:return: The positional index of the phase in relation to the other phases
|
||||
:rtype: int
|
||||
"""
|
||||
from bootstrapvz.common.phases import order
|
||||
return next(i for i, phase in enumerate(order) if phase is self)
|
||||
|
||||
def __cmp__(self, other):
|
||||
"""Compares the phase order in relation to the other phases
|
||||
:return int:
|
||||
"""
|
||||
return self.pos() - other.pos()
|
||||
|
||||
def __str__(self):
|
||||
"""String representation of the phase, the name suffices
|
||||
|
||||
Returns:
|
||||
string.
|
||||
"""
|
||||
:return: String representation of the phase
|
||||
:rtype: str
|
||||
"""
|
||||
return self.name
|
||||
|
|
|
@ -9,17 +9,16 @@ class PackageList(object):
|
|||
"""
|
||||
def __init__(self, name, target):
|
||||
"""
|
||||
Args:
|
||||
name (str): The name of the package
|
||||
target (str): The name of the target release
|
||||
:param str name: The name of the package
|
||||
:param str target: The name of the target release
|
||||
"""
|
||||
self.name = name
|
||||
self.target = target
|
||||
|
||||
def __str__(self):
|
||||
"""Converts the package into somehting that apt-get install can parse
|
||||
Returns:
|
||||
string.
|
||||
|
||||
:rtype: str
|
||||
"""
|
||||
if self.target is None:
|
||||
return self.name
|
||||
|
@ -31,23 +30,21 @@ class PackageList(object):
|
|||
"""
|
||||
def __init__(self, path):
|
||||
"""
|
||||
Args:
|
||||
path (str): The path to the local package
|
||||
:param str path: The path to the local package
|
||||
"""
|
||||
self.path = path
|
||||
|
||||
def __str__(self):
|
||||
"""
|
||||
Returns:
|
||||
string. The path to the local package
|
||||
:return: The path to the local package
|
||||
:rtype: string
|
||||
"""
|
||||
return self.path
|
||||
|
||||
def __init__(self, manifest_vars, source_lists):
|
||||
"""
|
||||
Args:
|
||||
manifest_vars (dict): The manifest variables
|
||||
source_lists (SourceLists): The sourcelists for apt
|
||||
:param dict manifest_vars: The manifest variables
|
||||
:param SourceLists source_lists: The sourcelists for apt
|
||||
"""
|
||||
self.manifest_vars = manifest_vars
|
||||
self.source_lists = source_lists
|
||||
|
@ -63,12 +60,11 @@ class PackageList(object):
|
|||
def add(self, name, target=None):
|
||||
"""Adds a package to the install list
|
||||
|
||||
Args:
|
||||
name (str): The name of the package to install, may contain manifest vars references
|
||||
target (str): The name of the target release for the package, may contain manifest vars references
|
||||
:param str name: The name of the package to install, may contain manifest vars references
|
||||
:param str target: The name of the target release for the package, may contain manifest vars references
|
||||
|
||||
Raises:
|
||||
PackageError
|
||||
:raises PackageError: When a package of the same name but with a different target has already been added.
|
||||
:raises PackageError: When the specified target release could not be found.
|
||||
"""
|
||||
from exceptions import PackageError
|
||||
name = name.format(**self.manifest_vars)
|
||||
|
@ -108,8 +104,7 @@ class PackageList(object):
|
|||
def add_local(self, package_path):
|
||||
"""Adds a local package to the installation list
|
||||
|
||||
Args:
|
||||
package_path (str): Path to the local package, may contain manifest vars references
|
||||
:param str package_path: Path to the local package, may contain manifest vars references
|
||||
"""
|
||||
package_path = package_path.format(**self.manifest_vars)
|
||||
self.install.append(self.Local(package_path))
|
||||
|
|
|
@ -6,8 +6,7 @@ class PreferenceLists(object):
|
|||
|
||||
def __init__(self, manifest_vars):
|
||||
"""
|
||||
Args:
|
||||
manifest_vars (dict): The manifest variables
|
||||
:param dict manifest_vars: The manifest variables
|
||||
"""
|
||||
# A dictionary with the name of the file in preferences.d as the key
|
||||
# That values are lists of Preference objects
|
||||
|
@ -18,12 +17,11 @@ class PreferenceLists(object):
|
|||
def add(self, name, preferences):
|
||||
"""Adds a preference to the apt preferences list
|
||||
|
||||
Args:
|
||||
name (str): Name of the file in preferences.list.d, may contain manifest vars references
|
||||
preferences (object): The preferences
|
||||
:param str name: Name of the file in preferences.list.d, may contain manifest vars references
|
||||
:param object preferences: The preferences
|
||||
"""
|
||||
name = name.format(**self.manifest_vars)
|
||||
self.preferences[name] = [Preference(p) for p in preferences]
|
||||
self.preferences[name] = [Preference(p) for p in preferences]
|
||||
|
||||
|
||||
class Preference(object):
|
||||
|
@ -32,18 +30,13 @@ class Preference(object):
|
|||
|
||||
def __init__(self, preference):
|
||||
"""
|
||||
Args:
|
||||
preference (dict): A apt preference dictionary
|
||||
|
||||
Raises:
|
||||
PreferenceError
|
||||
:param dict preference: A apt preference dictionary
|
||||
"""
|
||||
self.preference = preference
|
||||
self.preference = preference
|
||||
|
||||
def __str__(self):
|
||||
"""Convert the object into a preference block
|
||||
|
||||
Returns:
|
||||
string.
|
||||
:rtype: str
|
||||
"""
|
||||
return "Package: {package}\nPin: {pin}\nPin-Priority: {pin-priority}\n".format(**self.preference)
|
||||
return "Package: {package}\nPin: {pin}\nPin-Priority: {pin-priority}\n".format(**self.preference)
|
||||
|
|
|
@ -6,8 +6,7 @@ class SourceLists(object):
|
|||
|
||||
def __init__(self, manifest_vars):
|
||||
"""
|
||||
Args:
|
||||
manifest_vars (dict): The manifest variables
|
||||
:param dict manifest_vars: The manifest variables
|
||||
"""
|
||||
# A dictionary with the name of the file in sources.list.d as the key
|
||||
# That values are lists of Source objects
|
||||
|
@ -18,9 +17,8 @@ class SourceLists(object):
|
|||
def add(self, name, line):
|
||||
"""Adds a source to the apt sources list
|
||||
|
||||
Args:
|
||||
name (str): Name of the file in sources.list.d, may contain manifest vars references
|
||||
line (str): The line for the source file, may contain manifest vars references
|
||||
:param str name: Name of the file in sources.list.d, may contain manifest vars references
|
||||
:param str line: The line for the source file, may contain manifest vars references
|
||||
"""
|
||||
name = name.format(**self.manifest_vars)
|
||||
line = line.format(**self.manifest_vars)
|
||||
|
@ -31,11 +29,10 @@ class SourceLists(object):
|
|||
def target_exists(self, target):
|
||||
"""Checks whether the target exists in the sources list
|
||||
|
||||
Args:
|
||||
target (str): Name of the target to check for, may contain manifest vars references
|
||||
:param str target: Name of the target to check for, may contain manifest vars references
|
||||
|
||||
Returns:
|
||||
bool. Whether the target exists
|
||||
:return: Whether the target exists
|
||||
:rtype: bool
|
||||
"""
|
||||
target = target.format(**self.manifest_vars)
|
||||
# Run through all the sources and return True if the target exists
|
||||
|
@ -51,11 +48,9 @@ class Source(object):
|
|||
|
||||
def __init__(self, line):
|
||||
"""
|
||||
Args:
|
||||
line (str): A apt source line
|
||||
:param str line: A apt source line
|
||||
|
||||
Raises:
|
||||
SourceError
|
||||
:raises SourceError: When the source line cannot be parsed
|
||||
"""
|
||||
# Parse the source line and populate the class attributes with it
|
||||
# The format is taken from `man sources.list`
|
||||
|
@ -84,8 +79,7 @@ class Source(object):
|
|||
"""Convert the object into a source line
|
||||
This is pretty much the reverse of what we're doing in the initialization function.
|
||||
|
||||
Returns:
|
||||
string.
|
||||
:rtype: str
|
||||
"""
|
||||
options = ''
|
||||
if len(self.options) > 0:
|
||||
|
|
|
@ -16,15 +16,14 @@ class Task(object):
|
|||
"""
|
||||
def __repr__(cls):
|
||||
"""
|
||||
Returns:
|
||||
string.
|
||||
:return str: The full module path to the Task
|
||||
"""
|
||||
return cls.__module__ + '.' + cls.__name__
|
||||
|
||||
def __str__(cls):
|
||||
"""
|
||||
Returns:
|
||||
string.
|
||||
:return: The full module path to the Task
|
||||
:rtype: str
|
||||
"""
|
||||
return repr(cls)
|
||||
|
||||
|
@ -32,7 +31,6 @@ class Task(object):
|
|||
def run(cls, info):
|
||||
"""The run function, all work is done inside this function
|
||||
|
||||
:param info: The bootstrap info object.
|
||||
:type info: BootstrapInformation
|
||||
:param BootstrapInformation info: The bootstrap info object.
|
||||
"""
|
||||
pass
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
"""The tasklist module contains the TaskList class.
|
||||
.. module:: tasklist
|
||||
"""
|
||||
|
||||
from bootstrapvz.common.exceptions import TaskListError
|
||||
|
@ -22,10 +21,9 @@ class TaskList(object):
|
|||
The function that is called shall accept the taskset as its first argument and the manifest
|
||||
as its second argument.
|
||||
|
||||
Args:
|
||||
function (str): Name of the function to call
|
||||
manifest (Manifest): The manifest
|
||||
\*args: Additional arguments that should be passed to the function that is called
|
||||
:param str function: Name of the function to call
|
||||
:param Manifest manifest: The manifest
|
||||
:param list *args: Additional arguments that should be passed to the function that is called
|
||||
"""
|
||||
# Call 'function' on the provider
|
||||
getattr(manifest.modules['provider'], function)(self.tasks, manifest, *args)
|
||||
|
@ -38,9 +36,8 @@ class TaskList(object):
|
|||
def run(self, info, dry_run=False):
|
||||
"""Converts the taskgraph into a list and runs all tasks in that list
|
||||
|
||||
Args:
|
||||
info (dict): The bootstrap information object
|
||||
dry_run (bool): Whether to actually run the tasks or simply step through them
|
||||
:param dict info: The bootstrap information object
|
||||
:param bool dry_run: Whether to actually run the tasks or simply step through them
|
||||
"""
|
||||
# Create a list for us to run
|
||||
task_list = self.create_list()
|
||||
|
@ -109,8 +106,8 @@ class TaskList(object):
|
|||
def get_all_tasks(self):
|
||||
"""Gets a list of all task classes in the package
|
||||
|
||||
Returns:
|
||||
list. A list of all tasks in the package
|
||||
:return: A list of all tasks in the package
|
||||
:rtype: list
|
||||
"""
|
||||
# Get a generator that returns all classes in the package
|
||||
import os.path
|
||||
|
@ -126,15 +123,11 @@ class TaskList(object):
|
|||
def get_all_classes(self, path=None, prefix=''):
|
||||
""" Given a path to a package, this function retrieves all the classes in it
|
||||
|
||||
Args:
|
||||
path (str): Path to the package
|
||||
prefix (str): Name of the package followed by a dot
|
||||
|
||||
Returns:
|
||||
generator. A generator that yields classes
|
||||
|
||||
Raises:
|
||||
Exception
|
||||
:param str path: Path to the package
|
||||
:param str prefix: Name of the package followed by a dot
|
||||
:return: A generator that yields classes
|
||||
:rtype: generator
|
||||
:raises Exception: If a module cannot be inspected.
|
||||
"""
|
||||
import pkgutil
|
||||
import importlib
|
||||
|
@ -152,16 +145,14 @@ class TaskList(object):
|
|||
yield obj
|
||||
|
||||
def check_ordering(self, task):
|
||||
"""Checks the ordering of a task in relation to other tasks and their phases
|
||||
"""Checks the ordering of a task in relation to other tasks and their phases.
|
||||
|
||||
This function checks for a subset of what the strongly connected components algorithm does,
|
||||
but can deliver a more precise error message, namely that there is a conflict between
|
||||
what a task has specified as its predecessors or successors and in which phase it is placed.
|
||||
|
||||
Args:
|
||||
task (Task): The task to check the ordering for
|
||||
|
||||
Raises:
|
||||
TaskListError
|
||||
:param Task task: The task to check the ordering for
|
||||
:raises TaskListError: If there is a conflict between task precedence and phase precedence
|
||||
"""
|
||||
for successor in task.successors:
|
||||
# Run through all successors and check whether the phase of the task
|
||||
|
@ -182,13 +173,12 @@ class TaskList(object):
|
|||
|
||||
def strongly_connected_components(self, graph):
|
||||
"""Find the strongly connected components in a graph using Tarjan's algorithm.
|
||||
|
||||
Source: http://www.logarithmic.net/pfh-files/blog/01208083168/sort.py
|
||||
|
||||
Args:
|
||||
graph (dict): mapping of tasks to lists of successor tasks
|
||||
|
||||
Returns:
|
||||
list. List of tuples that are strongly connected comoponents
|
||||
:param dict graph: mapping of tasks to lists of successor tasks
|
||||
:return: List of tuples that are strongly connected comoponents
|
||||
:rtype: list
|
||||
"""
|
||||
|
||||
result = []
|
||||
|
@ -221,14 +211,13 @@ class TaskList(object):
|
|||
return result
|
||||
|
||||
def topological_sort(self, graph):
|
||||
"""Runs a topological sort on a graph
|
||||
"""Runs a topological sort on a graph.
|
||||
|
||||
Source: http://www.logarithmic.net/pfh-files/blog/01208083168/sort.py
|
||||
|
||||
Args:
|
||||
graph (dict): mapping of tasks to lists of successor tasks
|
||||
|
||||
Returns:
|
||||
list. A list of all tasks in the graph sorted according to ther dependencies
|
||||
:param dict graph: mapping of tasks to lists of successor tasks
|
||||
:return: A list of all tasks in the graph sorted according to ther dependencies
|
||||
:rtype: list
|
||||
"""
|
||||
count = {}
|
||||
for node in graph:
|
||||
|
|
Loading…
Add table
Reference in a new issue