- bin/wizard
Add a line describing your command in the helpstring
-- wizard/command/__init__.py
- Add the line "import commandname"
-
- wizard/command/commandname.py
Implement your command there as main(). Copy the function
signature and scaffolding from another file; it's non-trivial
file, so will we; installer script needs to be able to run
the installer to generate config files, so will this)
+- Fix parallel find to work with new style autoinstalls
+
- The great initial deploy:
- Turn on mediawiki new autoinstaller
- Migrate all mediawiki installs
import optparse
import sys
-# Add lib to path
sys.path.insert(0,os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
-import wizard.command
-from wizard.command import _command
+
+import wizard
+from wizard import command
def main():
usage = """usage: %prog COMMAND [ARGS]
parser.disable_interspersed_args()
_, args = parser.parse_args() # no global options
rest_argv = args[1:]
- baton = _command.OptionBaton()
+ baton = command.OptionBaton()
baton.add("--versions-path", dest="versions_path",
default="/afs/athena.mit.edu/contrib/scripts/sec-tools/store/versions",
help="Location of parallel-find output directory, or a file containing a newline separated list of 'all autoinstalls' (for testing).")
try:
- command = args[0]
+ command_name = args[0]
except IndexError:
parser.print_help()
raise SystemExit(1)
- if command == "help":
+ if command_name == "help":
try:
get_command(rest_argv[0]).main(['--help'], baton)
- except AttributeError:
+ except (AttributeError, ImportError):
parser.error("invalid action")
except IndexError:
parser.print_help()
raise SystemExit(1)
# Dispatch commands
try:
- command_module = get_command(command)
- except AttributeError:
+ command_module = get_command(command_name)
+ except (AttributeError, ImportError):
parser.error("invalid action")
command_module.main(rest_argv, baton)
def get_command(name):
+ __import__("wizard.command." + name)
return getattr(wizard.command, name)
if __name__ == "__main__":
-import migrate
-import massmigrate
-import info
-import summary
-import upgrade
+import logging
+import os
+import sys
+import optparse
+import errno
+
+import wizard
+
+logging_setup = False
+
+class Error(wizard.Error):
+ """Base error class for all command errors"""
+ pass
+
+class PermissionsError(Error):
+ def __init__(self, dir):
+ self.dir = dir
+ def __str__(self):
+ return """
+
+ERROR: You don't have permissions to access this directory.
+Do you have tokens for AFS with your root instance, and
+is your root instance on scripts-security-upd?
+
+You can check by running the commands 'klist' and
+'blanche scripts-security-upd'.
+"""
+
+class NoSuchDirectoryError(Error):
+ def __init__(self, dir):
+ self.dir = dir
+ def __str__(self):
+ return """
+
+ERROR: No such directory... check your typing
+"""
+
+def chdir(dir):
+ try:
+ os.chdir(dir)
+ except OSError as e:
+ if e.errno == errno.EACCES:
+ raise PermissionsError(dir)
+ elif e.errno == errno.ENOENT:
+ raise NoSuchDirectoryError(dir)
+ else: raise e
+
+def makeLogger(options, numeric_args):
+ global logging_setup
+ if logging_setup: return logging.getLogger()
+ context = " ".join(numeric_args)
+ logger = logging.getLogger()
+ logger.setLevel(logging.INFO)
+ stderr = logging.StreamHandler(sys.stderr)
+ stderr.setFormatter(logging.Formatter(" " * int(options.indent) + '%(levelname)s: %(message)s'))
+ dateFormat = "%H:%M:%S"
+ if options.context:
+ logformatter = logging.Formatter("%(asctime)s %(levelname)s -- " + context + ": %(message)s", dateFormat)
+ else:
+ logformatter = logging.Formatter("%(asctime)s %(levelname)s: %(message)s", dateFormat)
+ if not options.quiet: logger.addHandler(stderr)
+ else: logger.addHandler(NullLogHandler()) # prevent default
+ if options.log_file:
+ file = logging.FileHandler(options.log_file)
+ file.setFormatter(logformatter)
+ logger.addHandler(file)
+ if options.log_file_chmod:
+ os.chmod(options.log_file, int(options.log_file_chmod, 8))
+ if options.debug:
+ logger.setLevel(logging.DEBUG)
+ else:
+ stderr.setLevel(logging.WARNING)
+ if options.verbose or hasattr(options, "dry_run"):
+ stderr.setLevel(logging.INFO)
+ if options.log_file:
+ file.setLevel(logging.INFO)
+ logging_setup = True
+ return logger
+
+def makeBaseArgs(options, **grab):
+ """Takes parsed options, and breaks them back into a command
+ line string that we can pass into a subcommand"""
+ args = []
+ grab["log_file"]= "--log-file"
+ grab["debug"] = "--debug"
+ grab["verbose"] = "--verbose"
+ grab["indent"] = "--indent"
+ grab["quiet"] = "--quiet"
+ #grab["log_db"] = "--log-db"
+ for k,flag in grab.items():
+ value = getattr(options, k)
+ if not value and k != "indent": continue
+ args.append(flag)
+ if type(value) is not bool:
+ if k == "indent":
+ value += 4
+ args.append(str(value))
+ args.append("--context") # always have context for a subcommand
+ return args
+
+class NullLogHandler(logging.Handler):
+ """Log handler that doesn't do anything"""
+ def emit(self, record):
+ pass
+
+class WizardOptionParser(optparse.OptionParser):
+ """Configures some default user-level options"""
+ def __init__(self, *args, **kwargs):
+ kwargs["add_help_option"] = False
+ optparse.OptionParser.__init__(self, *args, **kwargs)
+ def parse_all(self, argv):
+ self.add_option("-h", "--help", action="help", help=optparse.SUPPRESS_HELP)
+ group = optparse.OptionGroup(self, "Common Options")
+ group.add_option("-v", "--verbose", dest="verbose", action="store_true",
+ default=False, help="Turns on verbose output")
+ group.add_option("--debug", dest="debug", action="store_true",
+ default=False, help="Turns on debugging output")
+ group.add_option("-q", "--quiet", dest="quiet", action="store_true",
+ default=False, help="Turns off output to stdout")
+ group.add_option("--log-file", dest="log_file",
+ default=None, help="Logs verbose output to file")
+ group.add_option("--log-file-chmod", dest="log_file_chmod",
+ default=None, help="Chmod the log file after opening. Number is octal. You must chmod the log file 666 and place the file in /tmp if subprocesses are running as different users.")
+ group.add_option("--indent", dest="indent",
+ default=0, help="Indents stdout, useful for nested calls")
+ group.add_option("--context", dest="context", action="store_true",
+ default=False, help="Adds context to logs, useful for parallel processing")
+ self.add_option_group(group)
+ options, numeric_args = self.parse_args(argv)
+ makeLogger(options, numeric_args)
+ return options, numeric_args
+
+class OptionBaton(object):
+ """Command classes may define options that they sub-commands may
+ use. Since wizard --global-command subcommand is not a supported
+ mode of operation, these options have to be passed down the command
+ chain until a option parser is ready to take it; this baton is
+ what is passed down."""
+ def __init__(self):
+ self.store = {}
+ def add(self, *args, **kwargs):
+ key = kwargs["dest"] # require this to be set
+ self.store[key] = optparse.make_option(*args, **kwargs)
+ def push(self, option_parser, *args):
+ """Hands off parameters to option parser"""
+ for key in args:
+ option_parser.add_option(self.store[key])
+++ /dev/null
-import logging
-import os
-import sys
-import optparse
-import errno
-
-import wizard
-
-logging_setup = False
-
-class Error(wizard.Error):
- """Base error class for all command errors"""
- pass
-
-class PermissionsError(Error):
- def __init__(self, dir):
- self.dir = dir
- def __str__(self):
- return """
-
-ERROR: You don't have permissions to access this directory.
-Do you have tokens for AFS with your root instance, and
-is your root instance on scripts-security-upd?
-
-You can check by running the commands 'klist' and
-'blanche scripts-security-upd'.
-"""
-
-class NoSuchDirectoryError(Error):
- def __init__(self, dir):
- self.dir = dir
- def __str__(self):
- return """
-
-ERROR: No such directory... check your typing
-"""
-
-def chdir(dir):
- try:
- os.chdir(dir)
- except OSError as e:
- if e.errno == errno.EACCES:
- raise PermissionsError(dir)
- elif e.errno == errno.ENOENT:
- raise NoSuchDirectoryError(dir)
- else: raise e
-
-def makeLogger(options, numeric_args):
- global logging_setup
- if logging_setup: return logging.getLogger()
- context = " ".join(numeric_args)
- logger = logging.getLogger()
- logger.setLevel(logging.INFO)
- stderr = logging.StreamHandler(sys.stderr)
- stderr.setFormatter(logging.Formatter(" " * int(options.indent) + '%(levelname)s: %(message)s'))
- dateFormat = "%H:%M:%S"
- if options.context:
- logformatter = logging.Formatter("%(asctime)s %(levelname)s -- " + context + ": %(message)s", dateFormat)
- else:
- logformatter = logging.Formatter("%(asctime)s %(levelname)s: %(message)s", dateFormat)
- if not options.quiet: logger.addHandler(stderr)
- else: logger.addHandler(NullLogHandler()) # prevent default
- if options.log_file:
- file = logging.FileHandler(options.log_file)
- file.setFormatter(logformatter)
- logger.addHandler(file)
- if options.log_file_chmod:
- os.chmod(options.log_file, int(options.log_file_chmod, 8))
- if options.debug:
- logger.setLevel(logging.DEBUG)
- else:
- stderr.setLevel(logging.WARNING)
- if options.verbose or hasattr(options, "dry_run"):
- stderr.setLevel(logging.INFO)
- if options.log_file:
- file.setLevel(logging.INFO)
- logging_setup = True
- return logger
-
-def makeBaseArgs(options, **grab):
- """Takes parsed options, and breaks them back into a command
- line string that we can pass into a subcommand"""
- args = []
- grab["log_file"]= "--log-file"
- grab["debug"] = "--debug"
- grab["verbose"] = "--verbose"
- grab["indent"] = "--indent"
- grab["quiet"] = "--quiet"
- #grab["log_db"] = "--log-db"
- for k,flag in grab.items():
- value = getattr(options, k)
- if not value and k != "indent": continue
- args.append(flag)
- if type(value) is not bool:
- if k == "indent":
- value += 4
- args.append(str(value))
- args.append("--context") # always have context for a subcommand
- return args
-
-class NullLogHandler(logging.Handler):
- """Log handler that doesn't do anything"""
- def emit(self, record):
- pass
-
-class WizardOptionParser(optparse.OptionParser):
- """Configures some default user-level options"""
- def __init__(self, *args, **kwargs):
- kwargs["add_help_option"] = False
- optparse.OptionParser.__init__(self, *args, **kwargs)
- def parse_all(self, argv):
- self.add_option("-h", "--help", action="help", help=optparse.SUPPRESS_HELP)
- group = optparse.OptionGroup(self, "Common Options")
- group.add_option("-v", "--verbose", dest="verbose", action="store_true",
- default=False, help="Turns on verbose output")
- group.add_option("--debug", dest="debug", action="store_true",
- default=False, help="Turns on debugging output")
- group.add_option("-q", "--quiet", dest="quiet", action="store_true",
- default=False, help="Turns off output to stdout")
- group.add_option("--log-file", dest="log_file",
- default=None, help="Logs verbose output to file")
- group.add_option("--log-file-chmod", dest="log_file_chmod",
- default=None, help="Chmod the log file after opening. Number is octal. You must chmod the log file 666 and place the file in /tmp if subprocesses are running as different users.")
- group.add_option("--indent", dest="indent",
- default=0, help="Indents stdout, useful for nested calls")
- group.add_option("--context", dest="context", action="store_true",
- default=False, help="Adds context to logs, useful for parallel processing")
- self.add_option_group(group)
- options, numeric_args = self.parse_args(argv)
- makeLogger(options, numeric_args)
- return options, numeric_args
-
-class OptionBaton(object):
- """Command classes may define options that they sub-commands may
- use. Since wizard --global-command subcommand is not a supported
- mode of operation, these options have to be passed down the command
- chain until a option parser is ready to take it; this baton is
- what is passed down."""
- def __init__(self):
- self.store = {}
- def add(self, *args, **kwargs):
- key = kwargs["dest"] # require this to be set
- self.store[key] = optparse.make_option(*args, **kwargs)
- def push(self, option_parser, *args):
- """Hands off parameters to option parser"""
- for key in args:
- option_parser.add_option(self.store[key])
import sys
import subprocess
-from wizard import deploy
-from wizard import log
+from wizard import deploy, log
def main(argv, baton):
options, args = parse_args(argv)
import pwd
import wizard
-from wizard import deploy
-from wizard import util
-from wizard import shell
-from wizard import sset
-from wizard.command import _command
+from wizard import deploy, util, shell, sset, command
from wizard.command import migrate
def main(argv, baton):
the scripts AFS patch. You may run it as an unpriviledged
user for testing purposes, but then you MUST NOT run this on
untrusted repositories."""
- parser = _command.WizardOptionParser(usage)
+ parser = command.WizardOptionParser(usage)
parser.add_option("--no-parallelize", dest="no_parallelize", action="store_true",
default=False, help="Turn off parallelization")
parser.add_option("--dry-run", dest="dry_run", action="store_true",
return options, args
def calculate_base_args(options):
- base_args = _command.makeBaseArgs(options, dry_run="--dry-run")
+ base_args = command.makeBaseArgs(options, dry_run="--dry-run")
if not options.debug:
base_args.append("--quiet")
return base_args
import errno
import sys
-from wizard import deploy
-from wizard import shell
-from wizard import util
-from wizard.command import _command
+from wizard import command, deploy, shell, util
def main(argv, baton):
options, args = parse_args(argv)
logging.debug("uid is %d" % os.getuid())
- _command.chdir(dir)
+ command.chdir(dir)
check_if_already_migrated(options)
version = calculate_version()
This command is meant to be run as the owner of the install
it is upgrading (see the scripts AFS kernel patch). Do
NOT run this command as root."""
- parser = _command.WizardOptionParser(usage)
+ parser = command.WizardOptionParser(usage)
parser.add_option("--dry-run", dest="dry_run", action="store_true",
default=False, help="Prints would would be run without changing anything")
parser.add_option("--force", "-f", dest="force", action="store_true",
except shell.CallError:
pass
-class Error(_command.Error):
+class Error(command.Error):
"""Base exception for all exceptions raised by migrate"""
pass
import optparse
import os
+import logging
-from wizard.command import _command
-
-# submodules
-import list
-import list_errors
-import version
-import count_exists
+import wizard
+from wizard import command, deploy
def main(argv, baton):
usage = """usage: %prog summary [ARGS] APPS
version Breakdown of autoinstalls by version (default)
Use %prog summary SUBCOMMAND --help for more information."""
- parser = _command.WizardOptionParser(usage)
+ parser = command.WizardOptionParser(usage)
parser.disable_interspersed_args()
baton.push(parser, "versions_path")
_, args = parser.parse_all(argv)
rest_argv = args[1:]
try:
- command = args[0]
+ command_name = args[0]
except IndexError:
- command = "version"
+ command_name = "version"
def get_command(name):
- return globals()[name.replace("-", "_")]
+ member = name.replace("-", "_")
+ module = "wizard.command.summary." + member
+ __import__(module)
+ return getattr(wizard.command.summary, member)
if command == "help":
try:
get_command(rest_argv[0]).main(['--help'], baton)
- except KeyError:
+ except ImportError:
parser.error("invalid action")
except IndexError:
parser.print_help()
raise SystemExit(1)
try:
- command_module = get_command(command)
- except KeyError:
+ command_module = get_command(command_name)
+ except ImportError:
parser.error("invalid action")
command_module.main(rest_argv, baton)
+## -- some generic helper stuff --
+
+def parse_install_lines(show, options, yield_errors = False):
+ if not show: show = deploy.applications
+ show = frozenset(show)
+ for line in deploy.getInstallLines(options.versions_path):
+ # construction
+ try:
+ d = deploy.Deployment.parse(line)
+ name = d.application.name
+ except deploy.NoSuchApplication as e:
+ if yield_errors:
+ yield e
+ continue
+ except deploy.Error:
+ # we consider this a worse error
+ logging.warning("Error with '%s'" % line.rstrip())
+ continue
+ # filter
+ if name + "-" + str(d.version) in show or name in show:
+ pass
+ else:
+ continue
+ # yield
+ yield d
+
+class Counter(object):
+ def __init__(self):
+ self.dict = {}
+ def count(self, value):
+ self.dict.setdefault(value, 0)
+ self.dict[value] += 1
+ def __getitem__(self, key):
+ return self.dict[key]
+ def __iter__(self):
+ return self.dict.__iter__()
+
+++ /dev/null
-import logging
-
-from wizard import deploy
-
-def parse_install_lines(show, options, yield_errors = False):
- if not show: show = deploy.applications
- show = frozenset(show)
- for line in deploy.getInstallLines(options.versions_path):
- # construction
- try:
- d = deploy.Deployment.parse(line)
- name = d.application.name
- except deploy.NoSuchApplication as e:
- if yield_errors:
- yield e
- continue
- except deploy.Error:
- # we consider this a worse error
- logging.warning("Error with '%s'" % line.rstrip())
- continue
- # filter
- if name + "-" + str(d.version) in show or name in show:
- pass
- else:
- continue
- # yield
- yield d
-
-class Counter(object):
- def __init__(self):
- self.dict = {}
- def count(self, value):
- self.dict.setdefault(value, 0)
- self.dict[value] += 1
- def __getitem__(self, key):
- return self.dict[key]
- def __iter__(self):
- return self.dict.__iter__()
-
import os
-from wizard.command import _command
-from wizard.command.summary import _summary
+from wizard import command
+from wizard.command import summary
def main(argv, baton):
options, args = parse_args(argv, baton)
value = args[0]
show = args[1:]
- for d in _summary.parse_install_lines(show, options):
+ for d in summary.parse_install_lines(show, options):
if os.path.exists(d.location + "/" + value):
print d.location
Examples:
%prog summary count-exists php.ini
Finds all autoinstalls that contain php.ini files"""
- parser = _command.WizardOptionParser(usage)
+ parser = command.WizardOptionParser(usage)
baton.push(parser, "versions_path")
options, args = parser.parse_all(argv)
if len(args) > 1:
import logging
import traceback
-from wizard.command import _command
-from wizard.command.summary import _summary
+from wizard import command
+from wizard.command import summary
def main(argv, baton):
options, show = parse_args(argv, baton)
errors = 0
- for d in _summary.parse_install_lines(show, options, True):
+ for d in summary.parse_install_lines(show, options, True):
if isinstance(d, Exception):
errors += 1
print d.location
List only MediaWiki autoinstalls
%prog summary list mediawiki-1.11.0
List only Mediawiki 1.11.0 autoinstalls"""
- parser = _command.WizardOptionParser(usage)
+ parser = command.WizardOptionParser(usage)
baton.push(parser, "versions_path")
options, args = parser.parse_all(argv)
if len(args) > 1:
import logging
-from wizard import deploy
-from wizard.command import _command
-from wizard.command.summary import _summary
+from wizard import deploy, command
+from wizard.command import summary
def main(argv, baton):
options, show = parse_args(argv, baton)
- for e in _summary.parse_install_lines(show, options, True):
+ for e in summary.parse_install_lines(show, options, True):
if not isinstance(e, deploy.Error):
if isinstance(e, Exception):
raise e
Lists all errors that occurred while parsing the versions
directory."""
- parser = _command.WizardOptionParser(usage)
+ parser = command.WizardOptionParser(usage)
baton.push(parser, "versions_path")
options, args = parser.parse_all(argv)
if len(args) > 1:
import math
-from wizard.command import _command
-from wizard.command.summary import _summary
+from wizard import command
+from wizard.command import summary
def main(argv, baton):
options, show = parse_args(argv, baton)
HISTOGRAM_WIDTH = 30
show = set()
- c_version = _summary.Counter()
- c_application = _summary.Counter()
- for d in _summary.parse_install_lines(show, options):
+ c_version = summary.Counter()
+ c_application = summary.Counter()
+ for d in summary.parse_install_lines(show, options):
version = d.app_version
c_version.count(version)
c_application.count(version.application)
Show graphs for all autoinstall versions
%prog summary list mediawiki
Show graph for MediaWiki autoinstall versions"""
- parser = _command.WizardOptionParser(usage)
+ parser = command.WizardOptionParser(usage)
baton.push(parser, "versions_path")
options, args = parser.parse_all(argv)
if len(args) > 1:
import errno
import tempfile
-from wizard import deploy
-from wizard import shell
-from wizard import util
-from wizard.command import _command
+from wizard import command, deploy, shell, util
# XXX: WARNING EXPERIMENTAL DANGER DANGER WILL ROBINSON
def main(argv, baton):
options, args = parse_args(argv)
dir = args[0]
- _command.chdir(dir)
+ command.chdir(dir)
if not os.path.isdir(".git"):
raise NotAutoinstallError()
try:
updating files and running .scripts/update.
WARNING: This is still experimental."""
- parser = _command.WizardOptionParser(usage)
+ parser = command.WizardOptionParser(usage)
parser.add_option("--dry-run", dest="dry_run", action="store_true",
default=False, help="Prints would would be run without changing anything")
options, args = parser.parse_all(argv)
parser.error("must specify directory")
return options, args
-class Error(_command.Error):
+class Error(command.Error):
"""Base exception for all exceptions raised by upgrade"""
pass
if version not in self.versions:
self.versions[version] = ApplicationVersion(distutils.version.LooseVersion(version), self)
return self.versions[version]
+ @staticmethod
+ def make(self, name):
+ pass
class ApplicationVersion(object):
"""Represents an abstract notion of a version for an application"""
import sys
import os
-import wizard as _wizard
+import wizard
from wizard import util
"""This is the path to the wizard executable as specified
def __init__(self, dry = False):
super(DummyParallelShell, self).__init__(dry=dry, max=1)
-class CallError(_wizard.Error):
+class CallError(wizard.Error):
def __init__(self, code, args, stdout, stderr):
self.code = code
self.args = args
-from wizard.deploy import *
-from distutils.version import LooseVersion as Version
-from datetime import datetime
-from dateutil.tz import tzoffset
-import os.path
+import distutils.version
+import datetime
+import dateutil.tz
-def getTestFile(file):
- return os.path.realpath(os.path.join(__file__, "..", file))
+from wizard import deploy
def test_deployment_parse():
- result = Deployment.parse("/afs/athena.mit.edu/user/e/z/ezyang/web_scripts/test-wiki:/afs/athena.mit.edu/contrib/scripts/deploy/mediawiki-1.11.0\n")
+ result = deploy.Deployment.parse("/afs/athena.mit.edu/user/e/z/ezyang/web_scripts/test-wiki:/afs/athena.mit.edu/contrib/scripts/deploy/mediawiki-1.11.0\n")
assert result.location == "/afs/athena.mit.edu/user/e/z/ezyang/web_scripts/test-wiki"
- assert result.getVersion() == Version("1.11.0")
- assert result.getApplication().name == "mediawiki"
+ assert result.version == distutils.version.LooseVersion("1.11.0")
+ assert result.application.name == "mediawiki"
def test_deployment_parse_nosuchapplication():
try:
- Deployment.parse("a:/foo/obviouslybogus-1.11.0\n")
+ deploy.Deployment.parse("a:/foo/obviouslybogus-1.11.0\n")
assert False
- except NoSuchApplication:
+ except deploy.NoSuchApplication:
pass
def test_deployment_from_dir():
pass # XXX
-def test_deploy_log_load():
- # this also is test_deploy_source_parse() and test_application_version_parse()
- log = DeployLog.load(getTestFile("deploy-log"))
-
- assert log[0].datetime == datetime(2006, 3, 23, 10, 7, 40, tzinfo=tzoffset(None, -5 * 60 * 60))
- assert log[0].user == "unknown"
- assert isinstance(log[0].source, TarballInstall)
- assert log[0].source.location == "/afs/athena.mit.edu/contrib/scripts/deploy/mediawiki.tar.gz"
- assert log[0].source.isDev == False
- assert log[0].version == applications["mediawiki"].getVersion('1.5.6')
-
- assert log[1].datetime == datetime(2007, 10, 17, 3, 38, 2, tzinfo=tzoffset(None, -4 * 60 * 60))
- assert log[1].user == "quentin@QUICHE-LORRAINE.MIT.EDU"
- assert isinstance(log[1].source, OldUpdate)
- assert log[1].source.isDev == True
- assert log[1].version == applications["mediawiki"].getVersion('1.5.6')
-
- assert log[2].datetime == datetime(2009, 6, 13, 21, 33, 0, tzinfo=tzoffset(None, -4 * 60 * 60))
- assert log[2].user == "ezyang@mit.edu"
- assert isinstance(log[2].source, WizardUpdate)
- assert log[2].version == applications["mediawiki"].getVersion('1.14.0-scripts')
--- /dev/null
+import os.path
+from dateutil.tz import tzoffset
+from datetime import datetime
+
+from wizard import deploy, log
+
+def getTestFile(file):
+ return os.path.realpath(os.path.join(__file__, "..", file))
+
+def test_deploy_log_load():
+ # this also is test_deploy_source_parse() and test_application_version_parse()
+ dlog = log.DeployLog.load(getTestFile("deploy-log"))
+
+ assert dlog[0].datetime == datetime(2006, 3, 23, 10, 7, 40, tzinfo=tzoffset(None, -5 * 60 * 60))
+ assert dlog[0].user == "unknown"
+ assert isinstance(dlog[0].source, log.TarballInstall)
+ assert dlog[0].source.location == "/afs/athena.mit.edu/contrib/scripts/deploy/mediawiki.tar.gz"
+ assert dlog[0].source.isDev == False
+ assert dlog[0].version == deploy.applications["mediawiki"].makeVersion('1.5.6')
+
+ assert dlog[1].datetime == datetime(2007, 10, 17, 3, 38, 2, tzinfo=tzoffset(None, -4 * 60 * 60))
+ assert dlog[1].user == "quentin@QUICHE-LORRAINE.MIT.EDU"
+ assert isinstance(dlog[1].source, log.OldUpdate)
+ assert dlog[1].source.isDev == True
+ assert dlog[1].version == deploy.applications["mediawiki"].makeVersion('1.5.6')
+
+ assert dlog[2].datetime == datetime(2009, 6, 13, 21, 33, 0, tzinfo=tzoffset(None, -4 * 60 * 60))
+ assert dlog[2].user == "ezyang@mit.edu"
+ assert isinstance(dlog[2].source, log.WizardUpdate)
+ assert dlog[2].version == deploy.applications["mediawiki"].makeVersion('1.14.0-scripts')
+