<commit_before>import json
import dcos
import pytest
import time

import dcos
import shakedown

from . import infinity_commons

from tests.command import (
    cassandra_api_url,
    check_health,
    get_dcos_command,
    get_cassandra_command,
    install,
    spin,
    uninstall,
    unset_ssl_verification,
)
from tests.defaults import DEFAULT_NODE_COUNT, PACKAGE_NAME

# install once up-front, reuse install for tests (MUCH FASTER):
def setup_module():
    unset_ssl_verification()

    uninstall()
    install()
    check_health()

def teardown_module():
    uninstall()

def get_first(collection, pred):
    for x in collection:
        if pred(x):
            return x

    return None

@pytest.mark.sanity
def test_connect():
    result = dcos.http.get(cassandra_api_url('connection'))
    body = result.json()
    assert len(body) == 3
    assert len(body["address"]) == DEFAULT_NODE_COUNT
    assert len(body["dns"]) == DEFAULT_NODE_COUNT
    assert body["vip"] == 'node.{}.l4lb.thisdcos.directory:9042'.format(PACKAGE_NAME)

@pytest.mark.sanity
def test_connect_address():
    result = dcos.http.get(cassandra_api_url('connection/address'))
    body = result.json()
    assert len(body) == DEFAULT_NODE_COUNT

@pytest.mark.sanity
def test_connect_dns():
    result = dcos.http.get(cassandra_api_url('connection/dns'))
    body = result.json()
    assert len(body) == DEFAULT_NODE_COUNT

@pytest.mark.sanity
def test_install():
    completed_plan = infinity_commons.get_and_verify_plan(
        lambda p: p['status'] == infinity_commons.PlanState.COMPLETE.value
    )
    assert completed_plan['status'] == infinity_commons.PlanState.COMPLETE.value

@pytest.mark.sanity
def test_env_unchanged():
    completed_plan = infinity_commons.get_and_verify_plan(
        lambda p: p['status'] == infinity_commons.PlanState.COMPLETE.value
    )
    assert completed_plan['status'] == infinity_commons.PlanState.COMPLETE.value

    mc = dcos.marathon.create_client()
    app = mc.get_app('/cassandra')
    app = infinity_commons.strip_meta(app)
    mc.update_app(app_id='/cassandra', payload=app)
    completed_plan = infinity_commons.get_and_verify_plan(
        lambda p: p['status'] == infinity_commons.PlanState.COMPLETE.value
    )
    assert completed_plan['status'] == infinity_commons.PlanState.COMPLETE.value

@pytest.mark.sanity
def test_nodes_increase_by_one():
    completed_plan = infinity_commons.get_and_verify_plan(
        lambda p: p['status'] == infinity_commons.PlanState.COMPLETE.value
    )
    mc = dcos.marathon.create_client()
    app = mc.get_app('/cassandra')
    app = infinity_commons.strip_meta(app)
    oe = app['env']
    env_node_count = int(oe['NODES']) + 1
    oe['NODES'] = str(env_node_count)
    app['env'] = oe
    print("Updated node count: {}".format(app['env']['NODES']))
    print(mc.update_app(app_id='/cassandra', payload=app, force=True))
    check_health()
    plan = infinity_commons.get_and_verify_plan(
        lambda p: (
            p['status'] == infinity_commons.PlanState.COMPLETE.value and
            len(infinity_commons.filter_phase(p, "Deploy")['steps']) == 4 and
            (
                infinity_commons.filter_phase(p, "Deploy")['steps'][env_node_count - 1]['status'] ==
                infinity_commons.PlanState.COMPLETE.value
            )
        )
    )
    print(plan)
    assert plan['status'] == infinity_commons.PlanState.COMPLETE.value
    # reinstall after increase:
    uninstall()
    install()
    check_health()

@pytest.mark.sanity
def test_nodes_decrease_by_one_should_fail():
    completed_plan = infinity_commons.get_and_verify_plan(
        lambda p: p['status'] == infinity_commons.PlanState.COMPLETE.value)
    mc = dcos.marathon.create_client()
    app = mc.get_app('/cassandra')
    app = infinity_commons.strip_meta(app)
    oe = app['env']
    env_node_count = int(oe['NODES']) - 1
    oe['NODES'] = str(env_node_count)
    app['env'] = oe
    print("Updated node count: {}".format(app['env']['NODES']))
    print(mc.update_app(app_id='/cassandra', payload=app, force=True))
    check_health()
    plan = infinity_commons.get_and_verify_plan(
        lambda p: (p['status'] == infinity_commons.PlanState.ERROR.value and
                   len(infinity_commons.filter_phase(p, "Deploy")['steps']) == 3))
    print(plan)
    assert plan['status'] == infinity_commons.PlanState.ERROR.value

    # Revert
    oe = app['env']
    env_node_count = int(oe['NODES']) + 1
    oe['NODES'] = str(env_node_count)
    app['env'] = oe
    print("Reverted node count: {}".format(app['env']['NODES']))
    print(mc.update_app(app_id='/cassandra', payload=app, force=True))
    check_health()
    plan = infinity_commons.get_and_verify_plan(
        lambda p: (p['status'] == infinity_commons.PlanState.COMPLETE.value) and
        (len(infinity_commons.filter_phase(p, "Deploy")['steps']) == 3))
    print(plan)
    assert plan['status'] == infinity_commons.PlanState.COMPLETE.value

@pytest.mark.sanity
def test_change_disk_should_fail():
    completed_plan = infinity_commons.get_and_verify_plan(
        lambda p: p['status'] == infinity_commons.PlanState.COMPLETE.value
    )
    mc = dcos.marathon.create_client()
    app = mc.get_app('/cassandra')
    app = infinity_commons.strip_meta(app)
    oe = app['env']
    disk = int(oe['CASSANDRA_DISK_MB']) - 1
    oe['CASSANDRA_DISK_MB'] = str(disk)
    app['env'] = oe
    print("Updated CASSANDRA_DISK_MB: {}".format(app['env']['CASSANDRA_DISK_MB']))
    print(mc.update_app(app_id='/cassandra', payload=app, force=True))
    check_health()
    plan = infinity_commons.get_and_verify_plan(
        lambda p: p['status'] == infinity_commons.PlanState.ERROR.value
    )
    print(plan)
    assert plan['status'] == infinity_commons.PlanState.ERROR.value

    # Revert
    oe = app['env']
    disk = int(oe['CASSANDRA_DISK_MB']) + 1
    oe['CASSANDRA_DISK_MB'] = str(disk)
    app['env'] = oe
    print("Reverted CASSANDRA_DISK_MB: {}".format(app['env']['CASSANDRA_DISK_MB']))
    print(mc.update_app(app_id='/cassandra', payload=app, force=True))
    check_health()
    plan = infinity_commons.get_and_verify_plan(
        lambda p: p['status'] == infinity_commons.PlanState.COMPLETE.value
    )
    print(plan)
    assert plan['status'] == infinity_commons.PlanState.COMPLETE.value

@pytest.mark.sanity
def test_cpus_increase_slightly():
    completed_plan = infinity_commons.get_and_verify_plan(
        lambda p: p['status'] == infinity_commons.PlanState.COMPLETE.value
    )
    mc = dcos.marathon.create_client()
    app = mc.get_app('/cassandra')
    app = infinity_commons.strip_meta(app)
    oe = app['env']
    cpu = float(oe['CASSANDRA_CPUS']) + 0.1
    oe['CASSANDRA_CPUS'] = str(cpu)
    app['env'] = oe
    print("Updated CASSANDRA_CPUS: {}".format(app['env']['CASSANDRA_CPUS']))
    print(mc.update_app(app_id='/cassandra', payload=app, force=True))
    check_health()
    plan = infinity_commons.get_and_verify_plan(
        lambda p: (
            p['status'] == infinity_commons.PlanState.COMPLETE.value and
            len(infinity_commons.filter_phase(p, "Deploy")['steps']) == 3
        )
    )
    print(plan)
    assert plan['status'] == infinity_commons.PlanState.COMPLETE.value

@pytest.mark.sanity
def test_is_suppressed():
    infinity_commons.get_and_verify_plan(lambda p: p['status'] == 'COMPLETE')
    time.sleep(5)
    response = dcos.http.get(cassandra_api_url('state/properties/suppressed'))
    response.raise_for_status()
    assert response.text == "true"

@pytest.mark.sanity
def test_node_is_replaced():
    infinity_commons.get_and_verify_plan(lambda p: p['status'] == 'COMPLETE')
    replaced_node_host = [
        t['slave_id'] for t in
        get_dcos_command('task --json') if t['name'] == 'node-0'
    ][0]
    replaced_node_task_id = get_cassandra_command('node replace node-0')[0]
    assert 'node-0' in replaced_node_task_id

    plan = infinity_commons.get_and_verify_plan(
        lambda p: (
            p['status'] == infinity_commons.PlanState.COMPLETE.value and
            len(infinity_commons.filter_phase(p, "Deploy")['steps']) == 3
        )
    )
    print(plan)
    assert plan['status'] == infinity_commons.PlanState.COMPLETE.value

    # Check that we've created a new task with a new id, waiting until a new one comes up.
    def get_status():
        first_node0 = get_first(get_dcos_command('task --json'), lambda t: t['name'] == 'node-0')
        if first_node0:
            return first_node0['id']
        return None

    def success_predicate(task_id):
        return task_id and (task_id != replaced_node_task_id), 'Task ID for replaced node did not change'

    spin(get_status, success_predicate)

    # Check cluster status with nodetool to assure that the new node has rejoined the cluster
    # and the old node has been removed, waiting until it's running (status "UN").
    def get_status():
        node1_host = get_first(
            get_first(get_dcos_command('task --json'), lambda t: t['name'] == 'node-1')['labels'],
            lambda label: label['key'] == 'offer_hostname'
        )['value']

        return shakedown.run_command_on_agent(
            node1_host,
            "docker run -t --net=host pitrho/cassandra-nodetool nodetool -p 7199 status"
        )

    def success_predicate(status):
        command_succeeded, status = status
        succeeded = (
            command_succeeded and
            len([x for x in status.split('\n') if x.startswith('UN')]) == DEFAULT_NODE_COUNT
        )

        return succeeded, 'Node did not successfully rejoin cluster'

    spin(get_status, success_predicate)
<commit_msg>Revert "Spot fix for actual test failure; probably the whole file needs this change, but that's another JIRA."<commit_after>import json
import dcos
import pytest
import time

import dcos
import shakedown

from . import infinity_commons

from tests.command import (
    cassandra_api_url,
    check_health,
    get_dcos_command,
    get_cassandra_command,
    install,
    spin,
    uninstall,
    unset_ssl_verification,
)
from tests.defaults import DEFAULT_NODE_COUNT, PACKAGE_NAME

# install once up-front, reuse install for tests (MUCH FASTER):
def setup_module():
    unset_ssl_verification()

    uninstall()
    install()
    check_health()

def teardown_module():
    uninstall()

def get_first(collection, pred):
    for x in collection:
        if pred(x):
            return x

    return None

@pytest.mark.sanity
def test_connect():
    result = dcos.http.get(cassandra_api_url('connection'))
    body = result.json()
    assert len(body) == 3
    assert len(body["address"]) == DEFAULT_NODE_COUNT
    assert len(body["dns"]) == DEFAULT_NODE_COUNT
    assert body["vip"] == 'node.{}.l4lb.thisdcos.directory:9042'.format(PACKAGE_NAME)

@pytest.mark.sanity
def test_connect_address():
    result = dcos.http.get(cassandra_api_url('connection/address'))
    body = result.json()
    assert len(body) == DEFAULT_NODE_COUNT

@pytest.mark.sanity
def test_connect_dns():
    result = dcos.http.get(cassandra_api_url('connection/dns'))
    body = result.json()
    assert len(body) == DEFAULT_NODE_COUNT

@pytest.mark.sanity
def test_install():
    completed_plan = infinity_commons.get_and_verify_plan(
        lambda p: p['status'] == infinity_commons.PlanState.COMPLETE.value
    )
    assert completed_plan['status'] == infinity_commons.PlanState.COMPLETE.value

@pytest.mark.sanity
def test_env_unchanged():
    completed_plan = infinity_commons.get_and_verify_plan(
        lambda p: p['status'] == infinity_commons.PlanState.COMPLETE.value
    )
    assert completed_plan['status'] == infinity_commons.PlanState.COMPLETE.value

    mc = dcos.marathon.create_client()
    app = mc.get_app('/cassandra')
    app = infinity_commons.strip_meta(app)
    mc.update_app(app_id='/cassandra', payload=app)
    completed_plan = infinity_commons.get_and_verify_plan(
        lambda p: p['status'] == infinity_commons.PlanState.COMPLETE.value
    )
    assert completed_plan['status'] == infinity_commons.PlanState.COMPLETE.value

@pytest.mark.sanity
def test_nodes_increase_by_one():
    completed_plan = infinity_commons.get_and_verify_plan(
        lambda p: p['status'] == infinity_commons.PlanState.COMPLETE.value
    )
    mc = dcos.marathon.create_client()
    app = mc.get_app('/cassandra')
    app = infinity_commons.strip_meta(app)
    oe = app['env']
    env_node_count = int(oe['NODES']) + 1
    oe['NODES'] = str(env_node_count)
    app['env'] = oe
    print("Updated node count: {}".format(app['env']['NODES']))
    print(mc.update_app(app_id='/cassandra', payload=app, force=True))
    check_health()
    plan = infinity_commons.get_and_verify_plan(
        lambda p: (
            p['status'] == infinity_commons.PlanState.COMPLETE.value and
            len(infinity_commons.filter_phase(p, "Deploy")['steps']) == 4 and
            (
                infinity_commons.filter_phase(p, "Deploy")['steps'][env_node_count - 1]['status'] ==
                infinity_commons.PlanState.COMPLETE.value
            )
        )
    )
    print(plan)
    assert plan['status'] == infinity_commons.PlanState.COMPLETE.value
    # reinstall after increase:
    uninstall()
    install()
    check_health()

@pytest.mark.sanity
def test_nodes_decrease_by_one_should_fail():
    completed_plan = infinity_commons.get_and_verify_plan(
        lambda p: p['status'] == infinity_commons.PlanState.COMPLETE.value)
    mc = dcos.marathon.create_client()
    app = mc.get_app('/cassandra')
    app = infinity_commons.strip_meta(app)
    oe = app['env']
    env_node_count = int(oe['NODES']) - 1
    oe['NODES'] = str(env_node_count)
    app['env'] = oe
    print("Updated node count: {}".format(app['env']['NODES']))
    print(mc.update_app(app_id='/cassandra', payload=app, force=True))
    check_health()
    plan = infinity_commons.get_and_verify_plan(
        lambda p: (p['status'] == infinity_commons.PlanState.ERROR.value and
                   len(infinity_commons.filter_phase(p, "Deploy")['steps']) == 3))
    print(plan)
    assert plan['status'] == infinity_commons.PlanState.ERROR.value

    # Revert
    oe = app['env']
    env_node_count = int(oe['NODES']) + 1
    oe['NODES'] = str(env_node_count)
    app['env'] = oe
    print("Reverted node count: {}".format(app['env']['NODES']))
    print(mc.update_app(app_id='/cassandra', payload=app, force=True))
    check_health()
    plan = infinity_commons.get_and_verify_plan(
        lambda p: (p['status'] == infinity_commons.PlanState.COMPLETE.value) and
        (len(infinity_commons.filter_phase(p, "Deploy")['steps']) == 3))
    print(plan)
    assert plan['status'] == infinity_commons.PlanState.COMPLETE.value

@pytest.mark.sanity
def test_change_disk_should_fail():
    completed_plan = infinity_commons.get_and_verify_plan(
        lambda p: p['status'] == infinity_commons.PlanState.COMPLETE.value
    )
    mc = dcos.marathon.create_client()
    app = mc.get_app('/cassandra')
    app = infinity_commons.strip_meta(app)
    oe = app['env']
    disk = int(oe['CASSANDRA_DISK_MB']) - 1
    oe['CASSANDRA_DISK_MB'] = str(disk)
    app['env'] = oe
    print("Updated CASSANDRA_DISK_MB: {}".format(app['env']['CASSANDRA_DISK_MB']))
    print(mc.update_app(app_id='/cassandra', payload=app, force=True))
    check_health()
    plan = infinity_commons.get_and_verify_plan(
        lambda p: p['status'] == infinity_commons.PlanState.ERROR.value
    )
    print(plan)
    assert plan['status'] == infinity_commons.PlanState.ERROR.value

    # Revert
    oe = app['env']
    disk = int(oe['CASSANDRA_DISK_MB']) + 1
    oe['CASSANDRA_DISK_MB'] = str(disk)
    app['env'] = oe
    print("Reverted CASSANDRA_DISK_MB: {}".format(app['env']['CASSANDRA_DISK_MB']))
    print(mc.update_app(app_id='/cassandra', payload=app, force=True))
    check_health()
    plan = infinity_commons.get_and_verify_plan(
        lambda p: p['status'] == infinity_commons.PlanState.COMPLETE.value
    )
    print(plan)
    assert plan['status'] == infinity_commons.PlanState.COMPLETE.value

@pytest.mark.sanity
def test_cpus_increase_slightly():
    completed_plan = infinity_commons.get_and_verify_plan(
        lambda p: p['status'] == infinity_commons.PlanState.COMPLETE.value
    )
    mc = dcos.marathon.create_client()
    app = mc.get_app('/cassandra')
    app = infinity_commons.strip_meta(app)
    oe = app['env']
    cpu = float(oe['CASSANDRA_CPUS']) + 0.1
    oe['CASSANDRA_CPUS'] = str(cpu)
    app['env'] = oe
    print("Updated CASSANDRA_CPUS: {}".format(app['env']['CASSANDRA_CPUS']))
    print(mc.update_app(app_id='/cassandra', payload=app, force=True))
    check_health()
    plan = infinity_commons.get_and_verify_plan(
        lambda p: (
            p['status'] == infinity_commons.PlanState.COMPLETE.value and
            len(infinity_commons.filter_phase(p, "Deploy")['steps']) == 3
        )
    )
    print(plan)
    assert plan['status'] == infinity_commons.PlanState.COMPLETE.value

@pytest.mark.sanity
def test_is_suppressed():
    infinity_commons.get_and_verify_plan(lambda p: p['status'] == 'COMPLETE')
    time.sleep(5)
    response = dcos.http.get(cassandra_api_url('state/properties/suppressed'))
    response.raise_for_status()
    assert response.text == "true"

@pytest.mark.sanity
def test_node_is_replaced():
    infinity_commons.get_and_verify_plan(lambda p: p['status'] == 'COMPLETE')
    replaced_node_host = [
        t['slave_id'] for t in
        get_dcos_command('task --json') if t['name'] == 'node-0'
    ][0]
    replaced_node_task_id = get_cassandra_command('node replace node-0')[0]
    assert 'node-0' in replaced_node_task_id

    plan = infinity_commons.get_and_verify_plan(
        lambda p: (
            p['status'] == infinity_commons.PlanState.COMPLETE.value and
            len(infinity_commons.filter_phase(p, "Deploy")['steps']) == 3
        )
    )
    print(plan)
    assert plan['status'] == infinity_commons.PlanState.COMPLETE.value

    # Check that we've created a new task with a new id, waiting until a new one comes up.
    def get_status():
        return get_first(
            get_dcos_command('task --json'), lambda t: t['name'] == 'node-0'
        )['id']

    def success_predicate(task_id):
        return task_id != replaced_node_task_id, 'Task ID for replaced node did not change'

    spin(get_status, success_predicate)

    # Check cluster status with nodetool to assure that the new node has rejoined the cluster
    # and the old node has been removed, waiting until it's running (status "UN").
    def get_status():
        node1_host = get_first(
            get_first(get_dcos_command('task --json'), lambda t: t['name'] == 'node-1')['labels'],
            lambda label: label['key'] == 'offer_hostname'
        )['value']

        return shakedown.run_command_on_agent(
            node1_host,
            "docker run -t --net=host pitrho/cassandra-nodetool nodetool -p 7199 status"
        )

    def success_predicate(status):
        command_succeeded, status = status
        succeeded = (
            command_succeeded and
            len([x for x in status.split('\n') if x.startswith('UN')]) == DEFAULT_NODE_COUNT
        )

        return succeeded, 'Node did not successfully rejoin cluster'

    spin(get_status, success_predicate)
<|endoftext|>


<commit_before>#!/usr/bin/env python3
# Copyright (c) 2015-2016 The Bitcoin Core developers
# Copyright (c) 2017 The Bitcoin developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""
This test checks activation of UAHF and the different consensus
related to this activation.
It is derived from the much more complex p2p-fullblocktest.
"""

import time

from test_framework.blocktools import (
    create_block,
    create_coinbase,
    create_transaction,
    make_conform_to_ctor,
)
from test_framework.comptool import RejectResult, TestInstance, TestManager
from test_framework.key import CECKey
from test_framework.messages import (
    COIN,
    COutPoint,
    CTransaction,
    CTxIn,
    CTxOut,
    ToHex,
)
from test_framework.mininode import network_thread_start
from test_framework.script import (
    CScript,
    OP_CHECKSIG,
    OP_TRUE,
    SIGHASH_ALL,
    SIGHASH_FORKID,
    SignatureHashForkId,
)
from test_framework.test_framework import ComparisonTestFramework
from test_framework.util import assert_equal, assert_raises_rpc_error

# far into the future
REPLAY_PROTECTION_START_TIME = 2000000000

# Error due to invalid signature
RPC_INVALID_SIGNATURE_ERROR = "mandatory-script-verify-flag-failed (Signature must be zero for failed CHECK(MULTI)SIG operation) (code 16)"

class PreviousSpendableOutput(object):

    def __init__(self, tx=CTransaction(), n=-1):
        self.tx = tx
        self.n = n

class ReplayProtectionTest(ComparisonTestFramework):

    def set_test_params(self):
        self.num_nodes = 1
        self.setup_clean_chain = True
        self.block_heights = {}
        self.tip = None
        self.blocks = {}
        self.extra_args = [['-whitelist=127.0.0.1',
                            "-replayprotectionactivationtime={}".format(REPLAY_PROTECTION_START_TIME)]]

    def run_test(self):
        self.test = TestManager(self, self.options.tmpdir)
        self.test.add_all_connections(self.nodes)
        network_thread_start()
        self.nodes[0].setmocktime(REPLAY_PROTECTION_START_TIME)
        self.test.run()

    def next_block(self, number):
        if self.tip == None:
            base_block_hash = self.genesis_hash
            block_time = int(time.time()) + 1
        else:
            base_block_hash = self.tip.sha256
            block_time = self.tip.nTime + 1
        # First create the coinbase
        height = self.block_heights[base_block_hash] + 1
        coinbase = create_coinbase(height)
        coinbase.rehash()
        block = create_block(base_block_hash, coinbase, block_time)

        # Do PoW, which is cheap on regnet
        block.solve()
        self.tip = block
        self.block_heights[block.sha256] = height
        assert number not in self.blocks
        self.blocks[number] = block
        return block

    def get_tests(self):
        self.genesis_hash = int(self.nodes[0].getbestblockhash(), 16)
        self.block_heights[self.genesis_hash] = 0
        spendable_outputs = []

        # save the current tip so it can be spent by a later block
        def save_spendable_output():
            spendable_outputs.append(self.tip)

        # get an output that we previously marked as spendable
        def get_spendable_output():
            return PreviousSpendableOutput(spendable_outputs.pop(0).vtx[0], 0)

        # returns a test case that asserts that the current tip was accepted
        def accepted():
            return TestInstance([[self.tip, True]])

        # returns a test case that asserts that the current tip was rejected
        def rejected(reject=None):
            if reject is None:
                return TestInstance([[self.tip, False]])
            else:
                return TestInstance([[self.tip, reject]])

        # move the tip back to a previous block
        def tip(number):
            self.tip = self.blocks[number]

        # adds transactions to the block and updates state
        def update_block(block_number, new_transactions):
            block = self.blocks[block_number]
            block.vtx.extend(new_transactions)
            old_sha256 = block.sha256
            make_conform_to_ctor(block)
            block.hashMerkleRoot = block.calc_merkle_root()
            block.solve()
            # Update the internal state just like in next_block
            self.tip = block
            if block.sha256 != old_sha256:
                self.block_heights[
                    block.sha256] = self.block_heights[old_sha256]
                del self.block_heights[old_sha256]
            self.blocks[block_number] = block
            return block

        # shorthand
        block = self.next_block
        node = self.nodes[0]

        # Create a new block
        block(0)
        save_spendable_output()
        yield accepted()

        # Now we need that block to mature so we can spend the coinbase.
        test = TestInstance(sync_every_block=False)
        for i in range(99):
            block(5000 + i)
            test.blocks_and_transactions.append([self.tip, True])
            save_spendable_output()
        yield test

        # collect spendable outputs now to avoid cluttering the code later on
        out = []
        for i in range(100):
            out.append(get_spendable_output())

        # Generate a key pair to test P2SH sigops count
        private_key = CECKey()
        private_key.set_secretbytes(b"replayprotection")
        public_key = private_key.get_pubkey()

        # This is a little handier to use than the version in blocktools.py
        def create_fund_and_spend_tx(spend, forkvalue=0):
            # Fund transaction
            script = CScript([public_key, OP_CHECKSIG])
            txfund = create_transaction(
                spend.tx, spend.n, b'', 50 * COIN, script)
            txfund.rehash()

            # Spend transaction
            txspend = CTransaction()
            txspend.vout.append(CTxOut(50 * COIN - 1000, CScript([OP_TRUE])))
            txspend.vin.append(CTxIn(COutPoint(txfund.sha256, 0), b''))

            # Sign the transaction
            sighashtype = (forkvalue << 8) | SIGHASH_ALL | SIGHASH_FORKID
            sighash = SignatureHashForkId(
                script, txspend, 0, sighashtype, 50 * COIN)
            sig = private_key.sign(sighash) + \
                bytes(bytearray([SIGHASH_ALL | SIGHASH_FORKID]))
            txspend.vin[0].scriptSig = CScript([sig])
            txspend.rehash()

            return [txfund, txspend]

        def send_transaction_to_mempool(tx):
            tx_id = node.sendrawtransaction(ToHex(tx))
            assert(tx_id in set(node.getrawmempool()))
            return tx_id

        # Before the fork, no replay protection required to get in the mempool.
        txns = create_fund_and_spend_tx(out[0])
        send_transaction_to_mempool(txns[0])
        send_transaction_to_mempool(txns[1])

        # And txns get mined in a block properly.
        block(1)
        update_block(1, txns)
        yield accepted()

        # Replay protected transactions are rejected.
        replay_txns = create_fund_and_spend_tx(out[1], 0xffdead)
        send_transaction_to_mempool(replay_txns[0])
        assert_raises_rpc_error(-26, RPC_INVALID_SIGNATURE_ERROR,
                                node.sendrawtransaction, ToHex(replay_txns[1]))

        # And block containing them are rejected as well.
        block(2)
        update_block(2, replay_txns)
        yield rejected(RejectResult(16, b'blk-bad-inputs'))

        # Rewind bad block
        tip(1)

        # Create a block that would activate the replay protection.
        bfork = block(5555)
        bfork.nTime = REPLAY_PROTECTION_START_TIME - 1
        update_block(5555, [])
        yield accepted()

        for i in range(5):
            block(5100 + i)
            test.blocks_and_transactions.append([self.tip, True])
        yield test

        # Check we are just before the activation time
        assert_equal(node.getblockheader(node.getbestblockhash())['mediantime'],
                     REPLAY_PROTECTION_START_TIME - 1)

        # We are just before the fork, replay protected txns still are rejected
        assert_raises_rpc_error(-26, RPC_INVALID_SIGNATURE_ERROR,
                                node.sendrawtransaction, ToHex(replay_txns[1]))

        block(3)
        update_block(3, replay_txns)
        yield rejected(RejectResult(16, b'blk-bad-inputs'))

        # Rewind bad block
        tip(5104)

        # Send some non replay protected txns in the mempool to check
        # they get cleaned at activation.
        txns = create_fund_and_spend_tx(out[2])
        send_transaction_to_mempool(txns[0])
        tx_id = send_transaction_to_mempool(txns[1])

        # Activate the replay protection
        block(5556)
        yield accepted()

        # Check we just activated the replay protection
        assert_equal(node.getblockheader(node.getbestblockhash())['mediantime'],
                     REPLAY_PROTECTION_START_TIME)

        # Non replay protected transactions are not valid anymore,
        # so they should be removed from the mempool.
        assert(tx_id not in set(node.getrawmempool()))

        # Good old transactions are now invalid.
        send_transaction_to_mempool(txns[0])
        assert_raises_rpc_error(-26, RPC_INVALID_SIGNATURE_ERROR,
                                node.sendrawtransaction, ToHex(txns[1]))

        # They also cannot be mined
        block(4)
        update_block(4, txns)
        yield rejected(RejectResult(16, b'blk-bad-inputs'))

        # Rewind bad block
        tip(5556)

        # The replay protected transaction is now valid
        replay_tx0_id = send_transaction_to_mempool(replay_txns[0])
        replay_tx1_id = send_transaction_to_mempool(replay_txns[1])

        # Make sure the transaction are ready to be mined.
        tmpl = node.getblocktemplate()

        found_id0 = False
        found_id1 = False

        for txn in tmpl['transactions']:
            txid = txn['txid']
            if txid == replay_tx0_id:
                found_id0 = True
            elif txid == replay_tx1_id:
                found_id1 = True

        assert(found_id0 and found_id1)

        # And the mempool is still in good shape.
        assert(replay_tx0_id in set(node.getrawmempool()))
        assert(replay_tx1_id in set(node.getrawmempool()))

        # They also can also be mined
        block(5)
        update_block(5, replay_txns)
        yield accepted()

        # Ok, now we check if a reorg work properly across the activation.
        postforkblockid = node.getbestblockhash()
        node.invalidateblock(postforkblockid)
        assert(replay_tx0_id in set(node.getrawmempool()))
        assert(replay_tx1_id in set(node.getrawmempool()))

        # Deactivating replay protection.
        forkblockid = node.getbestblockhash()
        node.invalidateblock(forkblockid)
        # The funding tx is not evicted from the mempool, since it's valid in
        # both sides of the fork
        assert(replay_tx0_id in set(node.getrawmempool()))
        assert(replay_tx1_id not in set(node.getrawmempool()))

        # Check that we also do it properly on deeper reorg.
        node.reconsiderblock(forkblockid)
        node.reconsiderblock(postforkblockid)
        node.invalidateblock(forkblockid)
        assert(replay_tx0_id in set(node.getrawmempool()))
        assert(replay_tx1_id not in set(node.getrawmempool()))

if __name__ == '__main__':
    ReplayProtectionTest().main()
<commit_msg>Migrated abc-replay-protection off of ComparisonTestFramework<commit_after>#!/usr/bin/env python3
# Copyright (c) 2015-2016 The Bitcoin Core developers
# Copyright (c) 2017 The Bitcoin developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""
This test checks activation of UAHF and the different consensus
related to this activation.
It is derived from the much more complex p2p-fullblocktest.
"""

import time

from test_framework.blocktools import (
    create_block,
    create_coinbase,
    create_transaction,
    make_conform_to_ctor,
)
from test_framework.key import CECKey
from test_framework.messages import (
    COIN,
    COutPoint,
    CTransaction,
    CTxIn,
    CTxOut,
    ToHex,
)
from test_framework.mininode import network_thread_start, P2PDataStore
from test_framework.script import (
    CScript,
    OP_CHECKSIG,
    OP_TRUE,
    SIGHASH_ALL,
    SIGHASH_FORKID,
    SignatureHashForkId,
)
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import assert_equal, assert_raises_rpc_error

# far into the future
REPLAY_PROTECTION_START_TIME = 2000000000

# Error due to invalid signature
RPC_INVALID_SIGNATURE_ERROR = "mandatory-script-verify-flag-failed (Signature must be zero for failed CHECK(MULTI)SIG operation) (code 16)"

class PreviousSpendableOutput(object):

    def __init__(self, tx=CTransaction(), n=-1):
        self.tx = tx
        self.n = n

class ReplayProtectionTest(BitcoinTestFramework):

    def set_test_params(self):
        self.num_nodes = 1
        self.setup_clean_chain = True
        self.block_heights = {}
        self.tip = None
        self.blocks = {}
        self.extra_args = [['-whitelist=127.0.0.1',
                            "-replayprotectionactivationtime={}".format(REPLAY_PROTECTION_START_TIME)]]

    def next_block(self, number):
        if self.tip == None:
            base_block_hash = self.genesis_hash
            block_time = int(time.time()) + 1
        else:
            base_block_hash = self.tip.sha256
            block_time = self.tip.nTime + 1
        # First create the coinbase
        height = self.block_heights[base_block_hash] + 1
        coinbase = create_coinbase(height)
        coinbase.rehash()
        block = create_block(base_block_hash, coinbase, block_time)

        # Do PoW, which is cheap on regnet
        block.solve()
        self.tip = block
        self.block_heights[block.sha256] = height
        assert number not in self.blocks
        self.blocks[number] = block
        return block

    def run_test(self):
        node = self.nodes[0]
        node.add_p2p_connection(P2PDataStore())
        network_thread_start()
        node.p2p.wait_for_verack()
        node.setmocktime(REPLAY_PROTECTION_START_TIME)

        self.genesis_hash = int(node.getbestblockhash(), 16)
        self.block_heights[self.genesis_hash] = 0
        spendable_outputs = []

        # save the current tip so it can be spent by a later block
        def save_spendable_output():
            spendable_outputs.append(self.tip)

        # get an output that we previously marked as spendable
        def get_spendable_output():
            return PreviousSpendableOutput(spendable_outputs.pop(0).vtx[0], 0)

        # move the tip back to a previous block
        def tip(number):
            self.tip = self.blocks[number]

        # adds transactions to the block and updates state
        def update_block(block_number, new_transactions):
            block = self.blocks[block_number]
            block.vtx.extend(new_transactions)
            old_sha256 = block.sha256
            make_conform_to_ctor(block)
            block.hashMerkleRoot = block.calc_merkle_root()
            block.solve()
            # Update the internal state just like in next_block
            self.tip = block
            if block.sha256 != old_sha256:
                self.block_heights[
                    block.sha256] = self.block_heights[old_sha256]
                del self.block_heights[old_sha256]
            self.blocks[block_number] = block
            return block

        # shorthand
        block = self.next_block

        # Create a new block
        block(0)
        save_spendable_output()
        node.p2p.send_blocks_and_test([self.tip], node)

        # Now we need that block to mature so we can spend the coinbase.
        maturity_blocks = []
        for i in range(99):
            block(5000 + i)
            maturity_blocks.append(self.tip)
            save_spendable_output()
        node.p2p.send_blocks_and_test(maturity_blocks, node)

        # collect spendable outputs now to avoid cluttering the code later on
        out = []
        for i in range(100):
            out.append(get_spendable_output())

        # Generate a key pair to test P2SH sigops count
        private_key = CECKey()
        private_key.set_secretbytes(b"replayprotection")
        public_key = private_key.get_pubkey()

        # This is a little handier to use than the version in blocktools.py
        def create_fund_and_spend_tx(spend, forkvalue=0):
            # Fund transaction
            script = CScript([public_key, OP_CHECKSIG])
            txfund = create_transaction(
                spend.tx, spend.n, b'', 50 * COIN, script)
            txfund.rehash()

            # Spend transaction
            txspend = CTransaction()
            txspend.vout.append(CTxOut(50 * COIN - 1000, CScript([OP_TRUE])))
            txspend.vin.append(CTxIn(COutPoint(txfund.sha256, 0), b''))

            # Sign the transaction
            sighashtype = (forkvalue << 8) | SIGHASH_ALL | SIGHASH_FORKID
            sighash = SignatureHashForkId(
                script, txspend, 0, sighashtype, 50 * COIN)
            sig = private_key.sign(sighash) + \
                bytes(bytearray([SIGHASH_ALL | SIGHASH_FORKID]))
            txspend.vin[0].scriptSig = CScript([sig])
            txspend.rehash()

            return [txfund, txspend]

        def send_transaction_to_mempool(tx):
            tx_id = node.sendrawtransaction(ToHex(tx))
            assert(tx_id in set(node.getrawmempool()))
            return tx_id

        # Before the fork, no replay protection required to get in the mempool.
        txns = create_fund_and_spend_tx(out[0])
        send_transaction_to_mempool(txns[0])
        send_transaction_to_mempool(txns[1])

        # And txns get mined in a block properly.
        block(1)
        update_block(1, txns)
        node.p2p.send_blocks_and_test([self.tip], node)

        # Replay protected transactions are rejected.
        replay_txns = create_fund_and_spend_tx(out[1], 0xffdead)
        send_transaction_to_mempool(replay_txns[0])
        assert_raises_rpc_error(-26, RPC_INVALID_SIGNATURE_ERROR,
                                node.sendrawtransaction, ToHex(replay_txns[1]))

        # And block containing them are rejected as well.
        block(2)
        update_block(2, replay_txns)
        node.p2p.send_blocks_and_test(
            [self.tip], node, success=False, reject_reason='blk-bad-inputs')

        # Rewind bad block
        tip(1)

        # Create a block that would activate the replay protection.
        bfork = block(5555)
        bfork.nTime = REPLAY_PROTECTION_START_TIME - 1
        update_block(5555, [])
        node.p2p.send_blocks_and_test([self.tip], node)

        activation_blocks = []
        for i in range(5):
            block(5100 + i)
            activation_blocks.append(self.tip)
        node.p2p.send_blocks_and_test(activation_blocks, node)

        # Check we are just before the activation time
        assert_equal(node.getblockheader(node.getbestblockhash())['mediantime'],
                     REPLAY_PROTECTION_START_TIME - 1)

        # We are just before the fork, replay protected txns still are rejected
        assert_raises_rpc_error(-26, RPC_INVALID_SIGNATURE_ERROR,
                                node.sendrawtransaction, ToHex(replay_txns[1]))

        block(3)
        update_block(3, replay_txns)
        node.p2p.send_blocks_and_test(
            [self.tip], node, success=False, reject_reason='blk-bad-inputs')

        # Rewind bad block
        tip(5104)

        # Send some non replay protected txns in the mempool to check
        # they get cleaned at activation.
        txns = create_fund_and_spend_tx(out[2])
        send_transaction_to_mempool(txns[0])
        tx_id = send_transaction_to_mempool(txns[1])

        # Activate the replay protection
        block(5556)
        node.p2p.send_blocks_and_test([self.tip], node)

        # Check we just activated the replay protection
        assert_equal(node.getblockheader(node.getbestblockhash())['mediantime'],
                     REPLAY_PROTECTION_START_TIME)

        # Non replay protected transactions are not valid anymore,
        # so they should be removed from the mempool.
        assert(tx_id not in set(node.getrawmempool()))

        # Good old transactions are now invalid.
        send_transaction_to_mempool(txns[0])
        assert_raises_rpc_error(-26, RPC_INVALID_SIGNATURE_ERROR,
                                node.sendrawtransaction, ToHex(txns[1]))

        # They also cannot be mined
        block(4)
        update_block(4, txns)
        node.p2p.send_blocks_and_test(
            [self.tip], node, success=False, reject_reason='blk-bad-inputs')

        # Rewind bad block
        tip(5556)

        # The replay protected transaction is now valid
        replay_tx0_id = send_transaction_to_mempool(replay_txns[0])
        replay_tx1_id = send_transaction_to_mempool(replay_txns[1])

        # Make sure the transaction are ready to be mined.
        tmpl = node.getblocktemplate()

        found_id0 = False
        found_id1 = False

        for txn in tmpl['transactions']:
            txid = txn['txid']
            if txid == replay_tx0_id:
                found_id0 = True
            elif txid == replay_tx1_id:
                found_id1 = True

        assert(found_id0 and found_id1)

        # And the mempool is still in good shape.
        assert(replay_tx0_id in set(node.getrawmempool()))
        assert(replay_tx1_id in set(node.getrawmempool()))

        # They also can also be mined
        block(5)
        update_block(5, replay_txns)
        node.p2p.send_blocks_and_test([self.tip], node)

        # Ok, now we check if a reorg work properly across the activation.
        postforkblockid = node.getbestblockhash()
        node.invalidateblock(postforkblockid)
        assert(replay_tx0_id in set(node.getrawmempool()))
        assert(replay_tx1_id in set(node.getrawmempool()))

        # Deactivating replay protection.
        forkblockid = node.getbestblockhash()
        node.invalidateblock(forkblockid)
        # The funding tx is not evicted from the mempool, since it's valid in
        # both sides of the fork
        assert(replay_tx0_id in set(node.getrawmempool()))
        assert(replay_tx1_id not in set(node.getrawmempool()))

        # Check that we also do it properly on deeper reorg.
        node.reconsiderblock(forkblockid)
        node.reconsiderblock(postforkblockid)
        node.invalidateblock(forkblockid)
        assert(replay_tx0_id in set(node.getrawmempool()))
        assert(replay_tx1_id not in set(node.getrawmempool()))

if __name__ == '__main__':
    ReplayProtectionTest().main()
<|endoftext|>


<commit_before>#!/usr/bin/env python
# -*- coding: utf-8 -*-

from collections import defaultdict, namedtuple
import copy
import json
from pprint import pprint
import re
import subprocess

from genshi_message import components_for_genshi_message

blank_re = re.compile('^[\s\xa0]*$')
def is_present(string):
    return string and not re.match(blank_re, string)

def parse_file(source_file):
    return json.load(subprocess.Popen(
        ['node', 'node_modules/esprima/bin/esparse.js', source_file],
        stdout=subprocess.PIPE).stdout)

# : string with javascript expression statement -> expression
def parse_fragment(javascript):
    process = subprocess.Popen(
        ['node', 'node_modules/esprima/bin/esparse.js', '/dev/stdin'],
        stdin=subprocess.PIPE, stdout=subprocess.PIPE)
    process.stdin.write(javascript)
    return json.load(process.stdout)['body'][0]['expression']

def generate(expression):
    process = subprocess.Popen(
        ['node', 'node_modules/escodegen/bin/esgenerate.js', '/dev/stdin'],
        stdin=subprocess.PIPE, stdout=subprocess.PIPE)
    json.dump(expression, process.stdin)
    return process.stdout.read()

def objects_in_tree(tree):
    iterable = tree.values() if hasattr(tree, 'values') else tree
    if not hasattr(iterable, '__iter__'): return
    for child in iterable:
        if isinstance(child, dict):
            yield child
        if not isinstance(child, basestring):
            for x in objects_in_tree(child): yield x

def matches(obj, pat):
    if isinstance(pat, dict) and isinstance(obj, dict):
        return all(matches(obj[k], v) if obj.has_key(k) else False
            for k, v in pat.items())
    elif isinstance(pat, type(lambda x:x)):
        return pat(obj)
    else:
        return obj == pat

string_literal_pattern = {
    'type': 'Literal',
    'value': lambda v: isinstance(v, basestring)
}
def string_literals_in_tree(tree):
    for o in objects_in_tree(tree):
        if matches(o, string_literal_pattern):
            yield o
def is_string_literal(expression):
    return matches(expression, string_literal_pattern)

def literal_expression_for_jsonifyable(jsonifyable):
    return parse_fragment(json.dumps(jsonifyable))

message_pattern = {
    'type': 'CallExpression',
    'callee': {
        'type': 'Identifier',
        'name': 'i18n'
    }
}
def message_expressions_in_tree(tree):
    for o in objects_in_tree(tree):
        if matches(o, message_pattern):
            if not len(o['arguments']) == 1:
                raise ValueError("i18n function must have exactly one argument: line %(line)s column %(column)s" % o['loc']['start'])
            yield o

dom_node_pattern = {
    "type": "CallExpression",
    "callee": {
        "type": "MemberExpression",
        "object": {
            "type": "MemberExpression",
            "object": {
                "type": "Identifier",
                "name": "React"
            },
            "property": {
                "type": "Identifier",
                "name": "DOM"
            }
        },
        "property": {
            "type": "Identifier",
        }
    }
}
def is_dom_node(expression):
    return matches(expression, dom_node_pattern)

class Struct(object):
    def __init__(self, entries):
        self.__dict__.update(entries)

# def immediate_subexpressions(expression):
#     e = Struct(expression)
#     type = e.type
#     if type in ('ThisExpression', 'FunctionExpression', 'ArrowExpression', 'GraphExpression', 'GraphIndexExpression', 'Literal', 'Identifier'):
#         return []
#     elif type == 'ArrayExpression':
#         return e.elements
#     elif type == 'ObjectExpression':
#         return [property['value'] for property in e.properties]
#     elif type == 'SequenceExpression':
#         return e.expressions
#     elif type in ('UnaryExpression', 'UpdateExpression'):
#         return [e.argument]
#     elif type in ('BinaryExpression', 'AssignmentExpression', 'LogicalExpression'):
#         return [e.left, e.right]
#     elif type == 'ConditionalExpression':
#         return [e.test, e.alternate, e.consequent]
#     elif type in ('NewExpression', 'CallExpression'):
#         return [e.callee] + e.arguments
#     elif type == 'MemberExpression':
#         return [e.object, e.property] if e.computed else [e.object]
#     elif type == 'YieldExpression':
#         return [e.argument] if e.argument else []
#     elif type in ('ComprehensionExpression', 'GeneratorExpression'):
#         return [e.body] + [block.right for block in e.blocks] + ([e.filter] if e.filter else [])
#     elif type == 'LetExpression':
#         return sum([[head.init] if head.init else [] for head in e.head], [e.body])

def immediate_subexpressions(expression):
    e = Struct(expression)
    type = e.type
    if type in ('ThisExpression', 'FunctionExpression', 'ArrowExpression', 'GraphExpression', 'GraphIndexExpression', 'Literal', 'Identifier'):
        return []
    elif type == 'ArrayExpression':
        return []
    elif type == 'ObjectExpression':
        return []
    elif type == 'SequenceExpression':
        return []
    elif type in ('UnaryExpression', 'UpdateExpression'):
        return []
    elif type in ('BinaryExpression', 'AssignmentExpression', 'LogicalExpression'):
        return []
    elif type == 'ConditionalExpression':
        return []
    elif type in ('NewExpression', 'CallExpression'):
        return e.arguments[1:]
    elif type == 'MemberExpression':
        return []
    elif type == 'YieldExpression':
        return []
    elif type in ('ComprehensionExpression', 'GeneratorExpression'):
        return []
    elif type == 'LetExpression':
        return []

def contains_string_literals(expression):
    return any(is_string_literal(e) for e in objects_in_tree(expression))

def is_always_interesting(expression):
    return is_string_literal(expression)

def is_inherently_interesting(expression):
    return (is_always_interesting(expression) or
        is_dom_node(expression))

def is_interesting(expression):
    return (is_always_interesting(expression)
        or (is_inherently_interesting(expression)
            and any(is_interesting(child) for child in immediate_subexpressions(expression))))

def tree_with_property(expression, property, depth=0):
    yield "    "*depth + str(expression.get(property))
    if is_interesting(expression):
        for subexpr in immediate_subexpressions(expression):
            for x in tree_with_property(subexpr, property, depth+1): yield x

def expanded_babel_message_for_expression(expression, depth=1):
    if is_string_literal(expression):
        return expression['value'][:20]
    elif not is_interesting(expression):
        return "[%s:]" % expression.get('number')
    else:
        indent = "\n" + "    "*depth
        subs = [expanded_babel_message_for_expression(subexpr, depth+1) for subexpr in immediate_subexpressions(expression)]
        first_indent = indent if len(subs) else ""
        braces = "[]" if is_interesting(expression) else "<>"
        return "%s%s:%s%s%s" % (braces[0], expression.get('number'), first_indent, indent.join(subs), braces[1])

def babel_message_for_expression(expression):
    if is_string_literal(expression):
        return expression['value']
    elif not is_interesting(expression):
        return "[%s:]" % expression.get('number')
    else:
        subs = [babel_message_for_expression(subexpr) for subexpr in immediate_subexpressions(expression)]
        if expression.get('number') == 0:
            return "".join(subs)
        else:
            return "[%s:%s]" % (expression.get('number'), "".join(subs))

def is_numberable(expression):
    return expression['type'] == 'CallExpression'

def visit_numbers_upon_expressions(expression, visitor, count=0):
    if is_numberable(expression):
        visitor(expression, count)
        count = count + 1
    if is_interesting(expression):
        for subexpr in immediate_subexpressions(expression):
            count = visit_numbers_upon_expressions(subexpr, visitor, count)
    return count

def copies_arguments(f):
    def g(*args, **kwargs):
        return f(*[copy.deepcopy(x) for x in args],
                **{k: copy.deepcopy(v) for k, v in kwargs.items()})
    return g

# : expression -> (expression with numbers w/o children, expressions by number)
@copies_arguments
def understand(expression):
    expressions_by_number = {}

    def visitor(subexpr, count):
        subexpr['number'] = count
        expressions_by_number[count] = subexpr
    visit_numbers_upon_expressions(expression, visitor)

    for k, v in expressions_by_number.items():
        if is_interesting(v):
            expressions_by_number[k] = without_children(v)

    return expression, expressions_by_number

@copies_arguments
def without_children(expression):
    assert is_dom_node(expression)
    expression['arguments'] = expression['arguments'][:1]
    return expression

@copies_arguments
def with_added_children(expression, children):
    assert is_dom_node(expression)
    for c in children:
        expression['arguments'].append(c)
    return expression

def debug(expr):
    output = Struct({'babel':[], 'type': []})
    output.type = list(tree_with_property(expr, 'number'))
    output.babel = expanded_babel_message_for_expression(expr).split('\n')

    data = list(zip(*output.__dict__.values()))
    padding = 2
    col_width = max(len(word) for row in data for word in row) + padding
    for row in data:
        print "".join(word.ljust(col_width) for word in row)

translated = """
[1:There's a hole in my bucket]
[2:Dear [3:] Liza [4:]:]
[5:]
[6:There's a hole in my bucket]
[7:Dear Liza do-day]
"""

@copies_arguments
def filled_out(root, expressions_by_number, children_by_number):
    if is_dom_node(root):
        root = with_added_children(root, [
            filled_out(child, expressions_by_number, children_by_number)
                for child in children_by_number[root['number']]])
    return root

def children_by_number(tokens, expressions_by_number):
    children_by_number = defaultdict(list)
    numbers_seen = {0}
    context = 0
    for number, text in tokens:
        node = expressions_by_number[number]
        if not number in numbers_seen:
            children_by_number[context].append(node)
            numbers_seen.add(number)
        context = number
        if is_present(text):
            children_by_number[context].append(
                literal_expression_for_jsonifyable(text))
    return children_by_number

if __name__ == '__main__':
    program = parse_file('/Users/david/code/app-ido-i3/var/out/green-1/js/org-intake.js')
    expr = list(message_expressions_in_tree(program))[-1]['arguments'][0]
    expr, expressions_by_number = understand(expr)
    orig_message = babel_message_for_expression(expr)
    print "------"
    children_by_number = children_by_number(components_for_genshi_message(orig_message), expressions_by_number)
    recon = filled_out(expressions_by_number[0], expressions_by_number, children_by_number)
    # debug(recon)
    print generate(recon)
    print generate(expr)
    print "Are they equal?", generate(recon) == generate(expr)
<commit_msg>pull into function<commit_after>#!/usr/bin/env python
# -*- coding: utf-8 -*-

from collections import defaultdict, namedtuple
import copy
import json
from pprint import pprint
import re
import subprocess

from genshi_message import components_for_genshi_message

blank_re = re.compile('^[\s\xa0]*$')
def is_present(string):
    return string and not re.match(blank_re, string)

def parse_file(source_file):
    return json.load(subprocess.Popen(
        ['node', 'node_modules/esprima/bin/esparse.js', source_file],
        stdout=subprocess.PIPE).stdout)

# : string with javascript expression statement -> expression
def parse_fragment(javascript):
    process = subprocess.Popen(
        ['node', 'node_modules/esprima/bin/esparse.js', '/dev/stdin'],
        stdin=subprocess.PIPE, stdout=subprocess.PIPE)
    process.stdin.write(javascript)
    return json.load(process.stdout)['body'][0]['expression']

def generate(expression):
    process = subprocess.Popen(
        ['node', 'node_modules/escodegen/bin/esgenerate.js', '/dev/stdin'],
        stdin=subprocess.PIPE, stdout=subprocess.PIPE)
    json.dump(expression, process.stdin)
    return process.stdout.read()

def objects_in_tree(tree):
    iterable = tree.values() if hasattr(tree, 'values') else tree
    if not hasattr(iterable, '__iter__'): return
    for child in iterable:
        if isinstance(child, dict):
            yield child
        if not isinstance(child, basestring):
            for x in objects_in_tree(child): yield x

def matches(obj, pat):
    if isinstance(pat, dict) and isinstance(obj, dict):
        return all(matches(obj[k], v) if obj.has_key(k) else False
            for k, v in pat.items())
    elif isinstance(pat, type(lambda x:x)):
        return pat(obj)
    else:
        return obj == pat

string_literal_pattern = {
    'type': 'Literal',
    'value': lambda v: isinstance(v, basestring)
}
def string_literals_in_tree(tree):
    for o in objects_in_tree(tree):
        if matches(o, string_literal_pattern):
            yield o
def is_string_literal(expression):
    return matches(expression, string_literal_pattern)

def literal_expression_for_jsonifyable(jsonifyable):
    return parse_fragment(json.dumps(jsonifyable))

message_pattern = {
    'type': 'CallExpression',
    'callee': {
        'type': 'Identifier',
        'name': 'i18n'
    }
}
def message_expressions_in_tree(tree):
    for o in objects_in_tree(tree):
        if matches(o, message_pattern):
            if not len(o['arguments']) == 1:
                raise ValueError("i18n function must have exactly one argument: line %(line)s column %(column)s" % o['loc']['start'])
            yield o

dom_node_pattern = {
    "type": "CallExpression",
    "callee": {
        "type": "MemberExpression",
        "object": {
            "type": "MemberExpression",
            "object": {
                "type": "Identifier",
                "name": "React"
            },
            "property": {
                "type": "Identifier",
                "name": "DOM"
            }
        },
        "property": {
            "type": "Identifier",
        }
    }
}
def is_dom_node(expression):
    return matches(expression, dom_node_pattern)

class Struct(object):
    def __init__(self, entries):
        self.__dict__.update(entries)

# def immediate_subexpressions(expression):
#     e = Struct(expression)
#     type = e.type
#     if type in ('ThisExpression', 'FunctionExpression', 'ArrowExpression', 'GraphExpression', 'GraphIndexExpression', 'Literal', 'Identifier'):
#         return []
#     elif type == 'ArrayExpression':
#         return e.elements
#     elif type == 'ObjectExpression':
#         return [property['value'] for property in e.properties]
#     elif type == 'SequenceExpression':
#         return e.expressions
#     elif type in ('UnaryExpression', 'UpdateExpression'):
#         return [e.argument]
#     elif type in ('BinaryExpression', 'AssignmentExpression', 'LogicalExpression'):
#         return [e.left, e.right]
#     elif type == 'ConditionalExpression':
#         return [e.test, e.alternate, e.consequent]
#     elif type in ('NewExpression', 'CallExpression'):
#         return [e.callee] + e.arguments
#     elif type == 'MemberExpression':
#         return [e.object, e.property] if e.computed else [e.object]
#     elif type == 'YieldExpression':
#         return [e.argument] if e.argument else []
#     elif type in ('ComprehensionExpression', 'GeneratorExpression'):
#         return [e.body] + [block.right for block in e.blocks] + ([e.filter] if e.filter else [])
#     elif type == 'LetExpression':
#         return sum([[head.init] if head.init else [] for head in e.head], [e.body])

def immediate_subexpressions(expression):
    e = Struct(expression)
    type = e.type
    if type in ('ThisExpression', 'FunctionExpression', 'ArrowExpression', 'GraphExpression', 'GraphIndexExpression', 'Literal', 'Identifier'):
        return []
    elif type == 'ArrayExpression':
        return []
    elif type == 'ObjectExpression':
        return []
    elif type == 'SequenceExpression':
        return []
    elif type in ('UnaryExpression', 'UpdateExpression'):
        return []
    elif type in ('BinaryExpression', 'AssignmentExpression', 'LogicalExpression'):
        return []
    elif type == 'ConditionalExpression':
        return []
    elif type in ('NewExpression', 'CallExpression'):
        return e.arguments[1:]
    elif type == 'MemberExpression':
        return []
    elif type == 'YieldExpression':
        return []
    elif type in ('ComprehensionExpression', 'GeneratorExpression'):
        return []
    elif type == 'LetExpression':
        return []

def contains_string_literals(expression):
    return any(is_string_literal(e) for e in objects_in_tree(expression))

def is_always_interesting(expression):
    return is_string_literal(expression)

def is_inherently_interesting(expression):
    return (is_always_interesting(expression) or
        is_dom_node(expression))

def is_interesting(expression):
    return (is_always_interesting(expression)
        or (is_inherently_interesting(expression)
            and any(is_interesting(child) for child in immediate_subexpressions(expression))))

def tree_with_property(expression, property, depth=0):
    yield "    "*depth + str(expression.get(property))
    if is_interesting(expression):
        for subexpr in immediate_subexpressions(expression):
            for x in tree_with_property(subexpr, property, depth+1): yield x

def expanded_babel_message_for_expression(expression, depth=1):
    if is_string_literal(expression):
        return expression['value'][:20]
    elif not is_interesting(expression):
        return "[%s:]" % expression.get('number')
    else:
        indent = "\n" + "    "*depth
        subs = [expanded_babel_message_for_expression(subexpr, depth+1) for subexpr in immediate_subexpressions(expression)]
        first_indent = indent if len(subs) else ""
        braces = "[]" if is_interesting(expression) else "<>"
        return "%s%s:%s%s%s" % (braces[0], expression.get('number'), first_indent, indent.join(subs), braces[1])

def babel_message_for_expression(expression):
    if is_string_literal(expression):
        return expression['value']
    elif not is_interesting(expression):
        return "[%s:]" % expression.get('number')
    else:
        subs = [babel_message_for_expression(subexpr) for subexpr in immediate_subexpressions(expression)]
        if expression.get('number') == 0:
            return "".join(subs)
        else:
            return "[%s:%s]" % (expression.get('number'), "".join(subs))

def is_numberable(expression):
    return expression['type'] == 'CallExpression'

def visit_numbers_upon_expressions(expression, visitor, count=0):
    if is_numberable(expression):
        visitor(expression, count)
        count = count + 1
    if is_interesting(expression):
        for subexpr in immediate_subexpressions(expression):
            count = visit_numbers_upon_expressions(subexpr, visitor, count)
    return count

def copies_arguments(f):
    def g(*args, **kwargs):
        return f(*[copy.deepcopy(x) for x in args],
                **{k: copy.deepcopy(v) for k, v in kwargs.items()})
    return g

# : expression -> (expression with numbers w/o children, expressions by number)
@copies_arguments
def understand(expression):
    expressions_by_number = {}

    def visitor(subexpr, count):
        subexpr['number'] = count
        expressions_by_number[count] = subexpr
    visit_numbers_upon_expressions(expression, visitor)

    for k, v in expressions_by_number.items():
        if is_interesting(v):
            expressions_by_number[k] = without_children(v)

    return expression, expressions_by_number

@copies_arguments
def without_children(expression):
    assert is_dom_node(expression)
    expression['arguments'] = expression['arguments'][:1]
    return expression

@copies_arguments
def with_added_children(expression, children):
    assert is_dom_node(expression)
    for c in children:
        expression['arguments'].append(c)
    return expression

def debug(expr):
    output = Struct({'babel':[], 'type': []})
    output.type = list(tree_with_property(expr, 'number'))
    output.babel = expanded_babel_message_for_expression(expr).split('\n')

    data = list(zip(*output.__dict__.values()))
    padding = 2
    col_width = max(len(word) for row in data for word in row) + padding
    for row in data:
        print "".join(word.ljust(col_width) for word in row)

translated = """
[1:There's a hole in my bucket]
[2:Dear [3:] Liza [4:]:]
[5:]
[6:There's a hole in my bucket]
[7:Dear Liza do-day]
"""

@copies_arguments
def filled_out(root, expressions_by_number, children_by_number):
    if is_dom_node(root):
        root = with_added_children(root, [
            filled_out(child, expressions_by_number, children_by_number)
                for child in children_by_number[root['number']]])
    return root

def number_children(tokens, expressions_by_number):
    result = defaultdict(list)
    numbers_seen = {0}
    context = 0
    for number, text in tokens:
        node = expressions_by_number[number]
        if not number in numbers_seen:
            result[context].append(node)
            numbers_seen.add(number)
        context = number
        if is_present(text):
            result[context].append(
                literal_expression_for_jsonifyable(text))
    return result

def expression_translated_by_message(expression, message):
    expr, expressions_by_number = understand(expression)
    children_by_number = number_children(components_for_genshi_message(message), expressions_by_number)
    return filled_out(expressions_by_number[0], expressions_by_number, children_by_number)

if __name__ == '__main__':
    program = parse_file('/Users/david/code/app-ido-i3/var/out/green-1/js/org-intake.js')
    expr = list(message_expressions_in_tree(program))[-1]['arguments'][0]

    orig_message = babel_message_for_expression(understand(expr)[0])
    print orig_message
    ident = expression_translated_by_message(expr, orig_message)

    recon = expression_translated_by_message(expr, translated)
    print generate(recon)
    print generate(expr)
    print "Does the identity hold?", generate(ident) == generate(expr)
<|endoftext|>


<commit_before># -*- coding: utf-8 -*-
'''
The service module for FreeBSD
'''
from __future__ import absolute_import

# Import python libs
import logging
import os
import re

# Import salt libs
import salt.utils
from salt.exceptions import CommandExecutionError

__func_alias__ = {
    'reload_': 'reload'
}

log = logging.getLogger(__name__)

# Define the module's virtual name
__virtualname__ = 'service'

def __virtual__():
    '''
    Only for Mac OS X
    '''
    if not salt.utils.is_darwin():
        return (False, 'Failed to load the mac_service module:\n'
                       'Only available on Mac OS X systems.')

    if not os.path.exists('/bin/launchctl'):
        return (False, 'Failed to load the mac_service module:\n'
                       'Required binary not found: "/bin/launchctl"')

    return __virtualname__

def _parse_return(data):
    '''
    Parse a return in the format:
    ``Time Zone: America/Denver``
    to return only:
    ``America/Denver``

    Returns: The value portion of a return
    '''

    if ': ' in data:
        return data.split(': ')[1]
    if ':\n' in data:
        return data.split(':\n')[1]
    else:
        return data

def start(service_path, domain='system'):
    '''
    Bootstraps domains and services. See `man launchctl` on a Mac OS X El
    Capitan system for more details.

    .. note::
       If the service already exists it will be restarted

    :param str service_path: Full path to the plist file

    :param str domain: Target domain. May be one of the following:
    - system : this is the default
    - user/<uid> : <uid> is the user id
    - login/<asid> : <asid> is the audit session id
    - gui/<uid> : <uid> is the user id
    - session/<asid> : <asid> is the audit session id
    - pid/<pid> : <pid> is the process id

    :return: The process ID of the new service
    '''
    if not os.path.exists(service_path):
        msg = 'Service Path not found:\n' \
              'Path: {0}'.format(service_path)
        raise CommandExecutionError(msg)

    # Get service_target from service_path
    service_name = os.path.splitext(os.path.basename(service_path))[0]
    if domain.endswith('/'):
        service_target = '{0}{1}'.format(domain, service_name)
    else:
        service_target = '{0}/{1}'.format(domain, service_name)

    # Is service running
    if service_name in get_all():
        return False

    # Enable the Launch Daemon
    cmd = ['launchctl', 'enable', service_target]
    ret = __salt__['cmd.run_all'](cmd, python_shell=False)
    if ret['retcode']:
        msg = 'Failed to enable service:\n' \
              'Path: {0}\n'.format(service_path)
        msg += 'Error: {0}\n'.format(ret['stderr'])
        msg += 'StdOut: {0}'.format(ret['stdout'])
        raise CommandExecutionError(msg)

    # Bootstrap the Launch Daemon
    cmd = ['launchctl', 'bootstrap', domain, service_path]
    ret = __salt__['cmd.run_all'](cmd, python_shell=False)
    if ret['retcode']:
        if 'service already loaded' not in ret['stderr']:
            msg = 'Failed to bootstrap service:\n' \
                  'Path: {0}\n'.format(service_path)
            msg += 'Error: {0}\n'.format(ret['stderr'])
            msg += 'StdOut: {0}'.format(ret['stdout'])
            raise CommandExecutionError(msg)

    # Kickstart the Launch Daemon
    cmd = ['launchctl', 'kickstart', '-kp', service_target]
    ret = __salt__['cmd.run_all'](cmd, python_shell=False)
    if ret['retcode']:
        msg = 'Failed to kickstart service:\n' \
              'Path: {0}\n'.format(service_path)
        msg += 'Error: {0}\n'.format(ret['stderr'])
        msg += 'StdOut: {0}'.format(ret['stdout'])
        raise CommandExecutionError(msg)

    return service_name in get_all()

def stop(service_path, domain='system'):
    if not os.path.exists(service_path):
        msg = 'Service Path not found:\n' \
              'Path: {0}'.format(service_path)
        raise CommandExecutionError(msg)

    # Get service_target from service_path
    service_name = os.path.splitext(os.path.basename(service_path))[0]
    if domain.endswith('/'):
        service_target = '{0}{1}'.format(domain, service_name)
    else:
        service_target = '{0}/{1}'.format(domain, service_name)

    # Is service running
    if service_name not in get_all():
        return False

    # Disable the Launch Daemon
    cmd = ['launchctl', 'disable', service_target]
    ret = __salt__['cmd.run_all'](cmd, python_shell=False)
    if ret['retcode']:
        msg = 'Failed to enable service:\n' \
              'Path: {0}\n'.format(service_path)
        msg += 'Error: {0}\n'.format(ret['stderr'])
        msg += 'StdOut: {0}'.format(ret['stdout'])
        raise CommandExecutionError(msg)

    # Remove the Launch Daemon
    cmd = ['launchctl', 'bootout', domain, service_path]
    ret = __salt__['cmd.run_all'](cmd, python_shell=False)
    if ret['retcode']:
        msg = 'Failed to bootstrap service:\n' \
              'Path: {0}\n'.format(service_path)
        msg += 'Error: {0}\n'.format(ret['stderr'])
        msg += 'StdOut: {0}'.format(ret['stdout'])
        raise CommandExecutionError(msg)

    if service_target in get_all():

        cmd = ['launchctl', 'kill', 'SIGKILL', service_target]
        ret = __salt__['cmd.run_all'](cmd, python_shell=False)
        if ret['retcode']:
            msg = 'Failed to kill the service:\n' \
                  'Path: {0}\n'.format(service_path)
            msg += 'Error: {0}\n'.format(ret['stderr'])
            msg += 'StdOut: {0}'.format(ret['stdout'])
            raise CommandExecutionError(msg)

    return service_name not in get_all()

def restart(service_target):
    # Kickstart the Launch Daemon
    cmd = ['launchctl', 'kickstart', '-kp', service_target]
    ret = __salt__['cmd.run_all'](cmd, python_shell=False)
    if ret['retcode']:
        msg = 'Failed to kickstart service:\n' \
              'Path: {0}\n'.format(service_target)
        msg += 'Error: {0}\n'.format(ret['stderr'])
        msg += 'StdOut: {0}'.format(ret['stdout'])
        raise CommandExecutionError(msg)

    return not ret['stderr']

def status(name):
    # TODO: Move this to mac_status function if ever created
    cmd = ['launchctl', 'list']
    output = __salt__['cmd.run_stdout'](cmd)

    pids = ''
    for line in output.splitlines():
        if 'PID' in line:
            continue
        if re.search(name, line):
            if isinstance(line.split()[0], int):
                if pids:
                    pids += '\n'
                pids += line.split()[0]

    return pids

def reload_():
    pass

def available():
    pass

def missing():
    pass

def get_all():
    # This command is deprecated, however there is no new command in launchctl
    # to list daemons
    cmd = ['launchctl', 'list']
    ret = __salt__['cmd.run'](cmd)

    services = []
    for line in ret.splitlines():
        if line.split('\t')[2] != 'Label':
            services.append(line.split('\t')[2].strip())

    return sorted(services)
<commit_msg>Removed int check<commit_after># -*- coding: utf-8 -*-
'''
The service module for FreeBSD
'''
from __future__ import absolute_import

# Import python libs
import logging
import os
import re

# Import salt libs
import salt.utils
from salt.exceptions import CommandExecutionError

__func_alias__ = {
    'reload_': 'reload'
}

log = logging.getLogger(__name__)

# Define the module's virtual name
__virtualname__ = 'service'

def __virtual__():
    '''
    Only for Mac OS X
    '''
    if not salt.utils.is_darwin():
        return (False, 'Failed to load the mac_service module:\n'
                       'Only available on Mac OS X systems.')

    if not os.path.exists('/bin/launchctl'):
        return (False, 'Failed to load the mac_service module:\n'
                       'Required binary not found: "/bin/launchctl"')

    return __virtualname__

def _parse_return(data):
    '''
    Parse a return in the format:
    ``Time Zone: America/Denver``
    to return only:
    ``America/Denver``

    Returns: The value portion of a return
    '''

    if ': ' in data:
        return data.split(': ')[1]
    if ':\n' in data:
        return data.split(':\n')[1]
    else:
        return data

def start(service_path, domain='system'):
    '''
    Bootstraps domains and services. See `man launchctl` on a Mac OS X El
    Capitan system for more details.

    .. note::
       If the service already exists it will be restarted

    :param str service_path: Full path to the plist file

    :param str domain: Target domain. May be one of the following:
    - system : this is the default
    - user/<uid> : <uid> is the user id
    - login/<asid> : <asid> is the audit session id
    - gui/<uid> : <uid> is the user id
    - session/<asid> : <asid> is the audit session id
    - pid/<pid> : <pid> is the process id

    :return: The process ID of the new service
    '''
    if not os.path.exists(service_path):
        msg = 'Service Path not found:\n' \
              'Path: {0}'.format(service_path)
        raise CommandExecutionError(msg)

    # Get service_target from service_path
    service_name = os.path.splitext(os.path.basename(service_path))[0]
    if domain.endswith('/'):
        service_target = '{0}{1}'.format(domain, service_name)
    else:
        service_target = '{0}/{1}'.format(domain, service_name)

    # Is service running
    if service_name in get_all():
        return False

    # Enable the Launch Daemon
    cmd = ['launchctl', 'enable', service_target]
    ret = __salt__['cmd.run_all'](cmd, python_shell=False)
    if ret['retcode']:
        msg = 'Failed to enable service:\n' \
              'Path: {0}\n'.format(service_path)
        msg += 'Error: {0}\n'.format(ret['stderr'])
        msg += 'StdOut: {0}'.format(ret['stdout'])
        raise CommandExecutionError(msg)

    # Bootstrap the Launch Daemon
    cmd = ['launchctl', 'bootstrap', domain, service_path]
    ret = __salt__['cmd.run_all'](cmd, python_shell=False)
    if ret['retcode']:
        if 'service already loaded' not in ret['stderr']:
            msg = 'Failed to bootstrap service:\n' \
                  'Path: {0}\n'.format(service_path)
            msg += 'Error: {0}\n'.format(ret['stderr'])
            msg += 'StdOut: {0}'.format(ret['stdout'])
            raise CommandExecutionError(msg)

    # Kickstart the Launch Daemon
    cmd = ['launchctl', 'kickstart', '-kp', service_target]
    ret = __salt__['cmd.run_all'](cmd, python_shell=False)
    if ret['retcode']:
        msg = 'Failed to kickstart service:\n' \
              'Path: {0}\n'.format(service_path)
        msg += 'Error: {0}\n'.format(ret['stderr'])
        msg += 'StdOut: {0}'.format(ret['stdout'])
        raise CommandExecutionError(msg)

    return service_name in get_all()

def stop(service_path, domain='system'):
    if not os.path.exists(service_path):
        msg = 'Service Path not found:\n' \
              'Path: {0}'.format(service_path)
        raise CommandExecutionError(msg)

    # Get service_target from service_path
    service_name = os.path.splitext(os.path.basename(service_path))[0]
    if domain.endswith('/'):
        service_target = '{0}{1}'.format(domain, service_name)
    else:
        service_target = '{0}/{1}'.format(domain, service_name)

    # Is service running
    if service_name not in get_all():
        return False

    # Disable the Launch Daemon
    cmd = ['launchctl', 'disable', service_target]
    ret = __salt__['cmd.run_all'](cmd, python_shell=False)
    if ret['retcode']:
        msg = 'Failed to enable service:\n' \
              'Path: {0}\n'.format(service_path)
        msg += 'Error: {0}\n'.format(ret['stderr'])
        msg += 'StdOut: {0}'.format(ret['stdout'])
        raise CommandExecutionError(msg)

    # Remove the Launch Daemon
    cmd = ['launchctl', 'bootout', domain, service_path]
    ret = __salt__['cmd.run_all'](cmd, python_shell=False)
    if ret['retcode']:
        msg = 'Failed to bootstrap service:\n' \
              'Path: {0}\n'.format(service_path)
        msg += 'Error: {0}\n'.format(ret['stderr'])
        msg += 'StdOut: {0}'.format(ret['stdout'])
        raise CommandExecutionError(msg)

    if service_target in get_all():

        cmd = ['launchctl', 'kill', 'SIGKILL', service_target]
        ret = __salt__['cmd.run_all'](cmd, python_shell=False)
        if ret['retcode']:
            msg = 'Failed to kill the service:\n' \
                  'Path: {0}\n'.format(service_path)
            msg += 'Error: {0}\n'.format(ret['stderr'])
            msg += 'StdOut: {0}'.format(ret['stdout'])
            raise CommandExecutionError(msg)

    return service_name not in get_all()

def restart(service_target):
    # Kickstart the Launch Daemon
    cmd = ['launchctl', 'kickstart', '-kp', service_target]
    ret = __salt__['cmd.run_all'](cmd, python_shell=False)
    if ret['retcode']:
        msg = 'Failed to kickstart service:\n' \
              'Path: {0}\n'.format(service_target)
        msg += 'Error: {0}\n'.format(ret['stderr'])
        msg += 'StdOut: {0}'.format(ret['stdout'])
        raise CommandExecutionError(msg)

    return not ret['stderr']

def status(name):
    # TODO: Move this to mac_status function if ever created
    cmd = ['launchctl', 'list']
    output = __salt__['cmd.run_stdout'](cmd)

    pids = ''
    for line in output.splitlines():
        if 'PID' in line:
            continue
        if re.search(name, line):
            if pids:
                pids += '\n'
            pids += line.split()[0]

    return pids

def reload_():
    pass

def available():
    pass

def missing():
    pass

def get_all():
    # This command is deprecated, however there is no new command in launchctl
    # to list daemons
    cmd = ['launchctl', 'list']
    ret = __salt__['cmd.run'](cmd)

    services = []
    for line in ret.splitlines():
        if line.split('\t')[2] != 'Label':
            services.append(line.split('\t')[2].strip())

    return sorted(services)
<|endoftext|>