Convert param docs into parseable format.

This commit is contained in:
Anders Ingemann 2014-05-04 19:31:53 +02:00
parent ee6df57f3f
commit ee3fe0bf42
24 changed files with 168 additions and 240 deletions

View file

@ -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'))

View file

@ -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):

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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()

View file

@ -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

View file

@ -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)

View file

@ -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)

View file

@ -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)

View file

@ -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)

View file

@ -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

View file

@ -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)

View file

@ -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

View file

@ -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

View file

@ -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)

View file

@ -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)

View file

@ -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

View file

@ -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))

View file

@ -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)

View file

@ -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:

View file

@ -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

View file

@ -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: