Example #1
0
def deploy_with_domains(builder, target_dir, name, role_domains):
    """
    Register a file deployment.

    'role_domains' is a sequence of (role, domain) pairs. The deployment will
    take the roles and domains specified, and build them into a deployment at
    deploy/[name].

    More specifically, a rule will be created for label:

      "deployment:<name>/deployed"

    which depends on "package:(<domain>)*{<role}/postinstalled" for each
    (<role>, <domain>) pair in 'role_domains'.

    In other words, the deployment called 'name' will depend on the given roles
    in the appropriate domains having been "finished" (postinstalled).

    An "instructions applied" label "deployment:<name>/instructionsapplied"
    will also be created.

    The deployment should eventually be located at 'target_dir'.
    """

    the_action = FileDeploymentBuilder(role_domains, target_dir)

    dep_label = depend.Label(utils.LabelType.Deployment, name, None,
                             utils.LabelTag.Deployed)

    iapp_label = depend.Label(utils.LabelType.Deployment,
                              name,
                              None,
                              utils.LabelTag.InstructionsApplied,
                              transient=True)

    # We depend on every postinstall for every package in the roles

    deployment_rule = depend.Rule(dep_label, the_action)

    for role, domain in role_domains:
        role_label = depend.Label(utils.LabelType.Package,
                                  "*",
                                  role,
                                  utils.LabelTag.PostInstalled,
                                  domain=domain)
        deployment_rule.add(role_label)

    # The instructionsapplied label is standalone ..
    app_rule = depend.Rule(iapp_label, the_action)

    # Now add 'em ..
    builder.ruleset.add(deployment_rule)
    builder.ruleset.add(app_rule)

    # .. and deal with cleanup, which is entirely generic
    deployment.register_cleanup(builder, name)

    # .. and set the environment
    the_action.attach_env(builder)
Example #2
0
def register_cleanup(builder, deployment):
    """
    Register the rule you need to clean a deployment.

    Cleaning a deployment basically means we remove the directory
    and its deployed tag.
    """

    target_lbl = depend.Label(utils.LabelType.Deployment, deployment, None,
                              utils.LabelTag.Clean)
    rule = depend.Rule(target_lbl, CleanDeploymentBuilder())
    builder.ruleset.add(rule)
Example #3
0
def _inside_of_deploy(builder, name, the_action):
    """This implements the common code from the public 'deploy()' function.
    """
    dep_label = Label(utils.LabelType.Deployment, name, None,
                      utils.LabelTag.Deployed)

    deployment_rule = depend.Rule(dep_label, the_action)

    # We need to clean it as well, annoyingly ..
    deployment.register_cleanup(builder, name)

    builder.ruleset.add(deployment_rule)

    # InstructionsApplied is a standalone rule, invoked by the deployment
    iapp_label = Label(utils.LabelType.Deployment,
                       name,
                       None,
                       utils.LabelTag.InstructionsApplied,
                       transient=True)
    iapp_rule = depend.Rule(iapp_label, the_action)
    builder.ruleset.add(iapp_rule)
Example #4
0
def role_depends_on_deployment(builder, role, deployment, domain=None):
    """
    Make every package in the given role depend on the given deployment
    """

    tgt = depend.Label(utils.LabelType.Package, "*", role,
                       utils.LabelTag.PreConfig)
    the_rule = depend.Rule(tgt, None)
    the_rule.add(
        depend.Label(utils.LabelType.Deployment,
                     deployment,
                     None,
                     utils.LabelTag.Deployed,
                     domain=domain))
    builder.ruleset.add(the_rule)
Example #5
0
def package_depends_on_checkout(ruleset,
                                pkg_name,
                                role_name,
                                co_name,
                                action=None):
    """
    Make the given package depend on the given checkout

    * ruleset   - The ruleset to use - builder.ruleset, for example.
    * pkg_name  - The package which depends.
    * role_name - The role which depends. Can be '*' for a wildcard.
    * co_name   - The checkout which this package and role depends on.
    * action    - If non-None, specifies an Action to be invoked to get from
      the checkout to the package preconfig. If you are a normal (outside
      muddle itself) caller, then you will normally leave this None unless you
      are doing something deeply weird.
    """

    checkout = depend.Label(utils.LabelType.Checkout, co_name, None,
                            utils.LabelTag.CheckedOut)

    preconfig = depend.Label(utils.LabelType.Package, pkg_name, role_name,
                             utils.LabelTag.PreConfig)

    new_rule = depend.Rule(preconfig, action)
    new_rule.add(checkout)
    ruleset.add(new_rule)

    # We can't clean or distclean a package until we've checked out its checkout
    # Both are transient, as we don't need to remember we've done them, and
    # indeed they should be doable more than once
    clean = depend.Label(utils.LabelType.Package,
                         pkg_name,
                         role_name,
                         utils.LabelTag.Clean,
                         transient=True)
    ruleset.add(depend.depend_one(action, clean, checkout))

    distclean = depend.Label(utils.LabelType.Package,
                             pkg_name,
                             role_name,
                             utils.LabelTag.DistClean,
                             transient=True)
    ruleset.add(depend.depend_one(action, distclean, checkout))
Example #6
0
def deploy(builder, name, rolesThatUseThis=[], rolesNeededForThis=[]):
    """
    Register a tools deployment.

    This is used to:

    1. Set the environment for each role in 'rolesThatUseThis' so that
       PATH, LD_LIBRARY_PATH and PKG_CONFIG_PATH include the 'name'
       deployment

    2. Make deployment:<name>/deployed depend upon the 'rolesNeededForThis'

    3. Register cleanup for this deployment

    The intent is that we have a "tools" deployment, which provides useful
    host tools (for instance, something to mangle a file in a particular
    manner). Those roles which need to use such tools in their builds
    (normally in a Makefile.muddle) then need to have the environment set
    appropriately to allow them to find the tools (and ideally, not system
    provided tools which mighth have the same name).
    """

    tgt = depend.Label(utils.LabelType.Deployment, name, None,
                       utils.LabelTag.Deployed)

    for role in rolesThatUseThis:
        for tag in (utils.LabelTag.PreConfig, utils.LabelTag.Configured,
                    utils.LabelTag.Built, utils.LabelTag.Installed,
                    utils.LabelTag.PostInstalled):
            lbl = depend.Label(utils.LabelType.Package, "*", role, tag)
            env = builder.get_environment_for(lbl)
            attach_env(builder, role, env, name)

        deployment.role_depends_on_deployment(builder, role, name)

    the_rule = depend.Rule(tgt, ToolsDeploymentBuilder(rolesNeededForThis))
    builder.ruleset.add(the_rule)

    deployment.deployment_depends_on_roles(builder, name, rolesNeededForThis)

    deployment.register_cleanup(builder, name)
Example #7
0
def pkg_depends_on_deployment(builder, pkg, roles, deployment, domain=None):
    """
    Make this package depend on the given deployment

    Specifically, given each role 'r' in 'roles', make the label
    "package:<pkg>{<r>}/preconfig" depend on the label
    "deployment:<deployment>/deployed".

    If 'domain' is given, this is (currently) just used for the deploymet
    label.
    """
    deployment_label = depend.Label(utils.LabelType.Deployment,
                                    deployment,
                                    None,
                                    utils.LabelTag.Deployed,
                                    domain=domain)
    for i in roles:
        tgt = depend.Label(utils.LabelType.Package, pkg, i,
                           utils.LabelTag.PreConfig)
        the_rule = depend.Rule(tgt, None)
        the_rule.add(deployment_label)
        builder.ruleset.add(the_rule)
Example #8
0
def add_checkout_rules(builder, co_label, action):
    """
    Add the standard checkout rules to a ruleset for a checkout
    with name co_label. 'action' should be an instance of VcsCheckoutBuilder,
    which knows how to build a checkout: label, depending on its tag.
    """

    ruleset = builder.ruleset

    # All of the VCS tags are transient (well, with the obvious exception
    # of "checked_out" itself). So we need to be a little bit careful.

    # Make sure we have the correct basic tag
    if co_label.tag != utils.LabelTag.CheckedOut:
        co_label = co_label.copy_with_tag(utils.LabelTag.CheckedOut)

    # And we simply use the VcsCheckoutBuilder (as we assume it to be)
    # to build us
    co_rule = depend.Rule(co_label, action)
    ruleset.add(co_rule)

    # Pulled is a transient label.
    pulled_label = co_label.copy_with_tag(utils.LabelTag.Pulled,
                                          transient=True)
    # Since 'checked_out' is not transient, and since it seems reasonable
    # enough that "muddle pull" should check the checkout out if it has not
    # already been done, then we can make it depend upon the checked_out label...
    # Tell its rule that it depends on the checkout being checked out (!)
    rule = depend.Rule(pulled_label, action)
    rule.add(co_label)
    ruleset.add(rule)

    # Merged is very similar, and also depends on the checkout existing
    merged_label = co_label.copy_with_tag(utils.LabelTag.Merged,
                                          transient=True)
    rule = depend.Rule(merged_label, action)
    rule.add(co_label)
    ruleset.add(rule)

    ## We used to say that UpToDate depended on Pulled.
    ## Our nearest equivalent would be Merged depending on Pulled.
    ## But that's plainly not a useful dependency, so we shall ignore it.
    #depend.depend_chain(action,
    #                    uptodate_label,
    #                    [ utils.LabelTag.Pulled ], ruleset)

    # We don't really want 'push' to do a 'checkout', so instead we rely on
    # the action only doing something if the corresponding checkout has
    # been checked out. Which leaves the rule with no apparent dependencies
    pushed_label = co_label.copy_with_tag(utils.LabelTag.ChangesPushed,
                                          transient=True)
    rule = depend.Rule(pushed_label, action)
    ruleset.add(rule)

    # The same also applies to commit...
    committed_label = co_label.copy_with_tag(utils.LabelTag.ChangesCommitted,
                                             transient=True)
    rule = depend.Rule(committed_label, action)
    ruleset.add(rule)

    # Centralised VCSs, in general, want us to do a 'pull' (update) before
    # doing a 'commit', so we should try to honour that, if necessary
    if (action.must_pull_before_commit(builder, co_label)):
        rule.add(pulled_label)
Example #9
0
def depend_unit_test():
    """
    Some fairly simple tests for the dependency solver.
    """

    l1 = Label(utils.LabelType.Checkout, "co_1", "role_1",
               utils.LabelTag.CheckedOut)
    l2 = Label(utils.LabelType.Checkout, "co_1", "role_1",
               utils.LabelTag.Pulled)
    l3 = Label(utils.LabelType.Package, "pkg_1", "role_1",
               utils.LabelTag.PreConfig)
    l4 = Label(utils.LabelType.Deployment, "dep_1", "role_2",
               utils.LabelTag.Built)

    # Check label_from_string ..
    lx = Label.from_string("foo:bar{baz}/wombat[T]")
    lx_a = Label("foo", "bar", "baz", "wombat")
    assert lx == lx_a
    assert lx.transient
    assert not lx.system

    lx = Label.from_string("foo:bar/wombat[T]")
    lx_a = Label("foo", "bar", None, "wombat")
    assert lx == lx_a
    assert lx.transient
    assert not lx.system

    lx = Label.from_string("*:bar/wombat")
    assert (lx is not None)
    lx_a = Label("*", "bar", None, "wombat")
    assert lx == lx_a
    assert not lx.transient
    assert not lx.system

    lx = Label.from_string("*:wombat/*")
    assert lx is not None
    lx_a = Label("*", "wombat", None, "*")
    assert lx == lx_a
    assert not lx.transient
    assert not lx.system

    lx = Label.from_string(l1.__str__())
    assert lx is not None
    assert lx == l1

    lx = Label.from_string(l2.__str__())
    assert lx is not None
    assert lx == l2

    lx = Label.from_string(l3.__str__())
    assert lx is not None
    assert lx == l3

    lx = Label.from_string(l4.__str__())
    assert lx is not None
    assert lx == l4

    # Let's check that label matching works the way we think it does ..
    la1 = Label(type='*',
                name=l1.name,
                domain=l1.domain,
                role=l1.role,
                tag=l1.tag)

    la2 = Label(type=l1.type,
                name='*',
                domain=l1.domain,
                role=l1.role,
                tag=l1.tag)

    la3 = Label(type=l1.type, name='*', domain=l1.domain, role='*', tag=l1.tag)

    la4 = l1.copy_with_tag('*')

    assert l1.match(l1) == 0
    assert l2.match(l1) is None
    assert la1.match(l1) == -1
    assert l1.match(la1) == -1
    assert (l2.match(la4)) == -1
    assert l1.match(la3) == -2

    r1 = depend.Rule(l1, pkg.NoAction())

    r2 = depend.Rule(l2, pkg.NoAction())
    r2.add(l1)

    r3 = depend.Rule(l3, pkg.NoAction())
    r4 = depend.Rule(l4, pkg.NoAction())

    r3.add(l2)
    r4.add(l3)
    r4.add(l2)

    rs = depend.RuleSet()
    rs.add(r1)
    rs.add(r2)
    rs.add(r3)
    rs.add(r4)
    assert str(rs).strip() == """\
-----
checkout:co_1{role_1}/checked_out <-NoAction-- [ ]
checkout:co_1{role_1}/pulled <-NoAction-- [ checkout:co_1{role_1}/checked_out ]
deployment:dep_1{role_2}/built <-NoAction-- [ checkout:co_1{role_1}/pulled, package:pkg_1{role_1}/preconfig ]
package:pkg_1{role_1}/preconfig <-NoAction-- [ checkout:co_1{role_1}/pulled ]
-----"""

    r3_required_for = depend.needed_to_build(rs, l3)
    assert depend.rule_list_to_string(
        r3_required_for
    ) == "[ checkout:co_1{role_1}/checked_out <-NoAction-- [ ], checkout:co_1{role_1}/pulled <-NoAction-- [ checkout:co_1{role_1}/checked_out ], package:pkg_1{role_1}/preconfig <-NoAction-- [ checkout:co_1{role_1}/pulled ],  ]"

    r2_required_by = depend.required_by(rs, l2)
    assert depend.rule_list_to_string(
        r2_required_by
    ) == "[ checkout:co_1{role_1}/pulled, deployment:dep_1{role_2}/built, package:pkg_1{role_1}/preconfig,  ]"
Example #10
0
def create(builder, target_file, name, compressionMethod = None,
           pruneFunc = None):
    """
    Create a CPIO deployment and return it.

    * 'builder' is the muddle builder that is driving us

    * 'target_file' is the name of the CPIO file we want to create.
      Note that this may include a sub-path (for instance, "fred/file.cpio"
      or even "/fred/file.cpio").

    * 'name' is either:

        1. The name of the deployment that will contain this CPIO file
           (in the builder's default domain), or
        2. A deployment or package label, ditto

    * 'comporessionMethod' is the compression method to use:

        * None means no compression
        * 'gzip' means gzip
        * 'bzip2' means bzip2

    * if 'pruneFunc' is not None, it is a function to be called like
      pruneFunc(Hierarchy) to prune the hierarchy prior to packing. Usually
      something like deb.deb_prune, it's intended to remove spurious stuff like
      manpages from initrds and the like.

    Normal usage is thus something like::

        fw = cpio.create(builder, 'firmware.cpio', deployment)
        fw.copy_from_role(role1, '', '/')
        fw.copy_from_role(role2, 'bin', '/bin')
        fw.done()

    or::

        fw = cpio.create(builder, 'firmware.cpio', package('firmware', role))
        fw.copy_from_role(role, '', '/')
        fw.done()

    """

    if isinstance(name, basestring):
        label = depend.Label(LabelType.Deployment, name, None,
                             LabelTag.Deployed,
                             domain = builder.default_domain)
    elif isinstance(name, depend.Label):
        label = name
        if label.type not in (LabelType.Deployment, LabelType.Package):
            raise GiveUp("Third argument to muddled.deployments.cpio.create()"
                         " should be a string or a deployment/package label,"
                         " not a %s label"%label.type)

        if label.type == LabelType.Deployment and label.tag != LabelTag.Deployed:
            label = label.copy_with_tag(LabelTag.Deployed)
        elif label.type == LabelType.Package and label.tag != LabelTag.PostInstalled:
            label = label.copy_with_tag(LabelTag.PostInstalled)

    else:
        raise GiveUp("Third argument to muddled.deployments.cpio.create()"
                     " should be a string or a package/deployment label,"
                     " not %s"%type(name))

    the_action = CpioDeploymentBuilder(target_file, [], compressionMethod, pruneFunc)

    the_rule = depend.Rule(label, the_action)

    builder.ruleset.add(the_rule)

    if label.type == LabelType.Deployment:
        deployment.register_cleanup(builder, name)

    return CpioWrapper(builder, the_action, label)