#main test ve tests classlarim in icinde jsondaki butun tanimli elemanlar var. Main_test.parse_from_json(json_object)

#methodu icine bi json aldiginda json objesindeki gerekli elemanlari okuyup bu elemanlari kullanarak

#bir main_test objesi yaratir.

#Test classim da bu json dosyasindaki tests kismindaki elemanlar icin yarattim onun da kendine ozel parse json methodu var

#ve yine ayni islemi yapiyor.

#Main_Test.parse_from_json(json_object):

#input: json objesi (filepath ile alinabilir vs.)

#parsed_json maintest tipindeki obje icinde bir tane test listesi var, bu test listesinin icinde de testler var o testlerin id name ve commands i var
#bu commandslerde ayri bir liste her bir test icin o yuzden commandsden bi eleman cagirmak parsed_json.test[0].commands[] istedigimiz indexdeki elemani cagirabiliyoruz.
import json
#Reading a file
# f = open('jhipster.side', 'r+')
# # read()
# text = f.read()
# print(text)
# f.close()

class Main_Test:

    def __init__(self, id, version, url, tests, suites, urls, plugins):

        self.id = id
        self.version = version
        self.url = url
        self.tests = tests
        self.suites = suites
        self.urls = urls
        self.plugins = plugins

    def parse_from_json(json_object):

        if json_object is None:
            return None

        json_tests_list = json_object['tests']
        object_tests_list = []
        for json_test in json_tests_list:

            object_tests_list.append(Test.parse_from_json(json_test))

            return Main_Test(json_object["id"],
            json_object["version"],
            json_object["url"],
            object_tests_list,
            json_object["suites"],
            json_object["urls"],
            json_object["plugins"])

class Test:

    def __init__(self, id, name, commands):

        self.id = id
        self.name = name
        self.commands = commands

    def parse_from_json(json_object):

        if json_object is None:
            return None

        json_commands_list = json_object['commands']
        object_commands_list = []
        for json_test in json_commands_list:
            object_commands_list.append(Commands.parse_from_json(json_test))

        return Test(json_object["id"],
                    json_object["name"],
                    object_commands_list)

class Commands:

    def __init__(self, id, comment, command, target, targets, value):
        self.id = id
        self.comment = comment
        self.command = command
        self.target = target
        self.targets = targets
        self.value = value

    def parse_from_json(json_object):

        if json_object is None:
            return None

        return Commands(json_object["id"],
        json_object["comment"],
        json_object["command"],
        json_object["target"],
        json_object["targets"],
        json_object["value"])

with open("jhipster.side", "r") as read_file:

    data = json.load(read_file)
    parsed_json = Main_Test.parse_from_json(data)

    print(parsed_json.tests[0].commands[0].id)
    print(parsed_json.tests[0].id)
    print(parsed_json.tests[0].name)
    print(parsed_json.url)


import numpy as np
import pytest
from numpy.testing import assert_allclose, assert_array_equal
from scipy.optimize import minimize
from sklearn.isotonic import IsotonicRegression as skl_IsotonicRegression

from model_diagnostics._utils.isotonic import (
    IsotonicRegression,
    gpava,
    isotonic_regression,
    pava,
)
from model_diagnostics.scoring import PinballLoss, SquaredError

def mean_fun(x, w):
    return np.average(x, weights=w)

mean_fun.loss = SquaredError()  # type: ignore

def median_lower(x, w=None):
    return np.quantile(x, q=0.5, method="inverted_cdf")

median_lower.loss = PinballLoss(level=0.5)  # type: ignore

def median_upper(x, w=None):
    return -np.quantile(-np.asarray(x), q=0.5, method="inverted_cdf")

median_upper.loss = PinballLoss(level=0.5)  # type: ignore

def quantile80_lower(x, w=None):
    return np.quantile(x, q=0.8, method="inverted_cdf")

quantile80_lower.loss = PinballLoss(level=0.8)  # type: ignore

def quantile80_upper(x, w=None):
    return -np.quantile(-np.asarray(x), q=1 - 0.8, method="inverted_cdf")

quantile80_upper.loss = PinballLoss(level=0.8)  # type: ignore

def quantile10_lower(x, w=None):
    return np.quantile(x, q=0.1, method="inverted_cdf")

quantile10_lower.loss = PinballLoss(level=0.1)  # type: ignore

def quantile10_upper(x, w=None):
    return -np.quantile(-np.asarray(x), q=1 - 0.1, method="inverted_cdf")

quantile10_upper.loss = PinballLoss(level=0.1)  # type: ignore

def gpava_mean(x, w=None):
    return gpava(mean_fun, x, w)

@pytest.mark.parametrize("pava", [pava, gpava_mean])
def test_pava_simple(pava):
    # Test case of Busing 2020
    # https://doi.org/10.18637/jss.v102.c01
    y = [8, 4, 8, 2, 2, 0, 8]
    w = np.ones_like(y)
    x, r = pava(y, w)
    assert_array_equal(x, [4, 4, 4, 4, 4, 4, 8])
    assert_array_equal(r, [0, 6, 7])

    y = [9, 1, 8, 2, 7, 3, 6]
    w = None
    x, r = pava(y, w)
    assert_array_equal(x, [5, 5, 5, 5, 5, 5, 6])
    assert_array_equal(r, [0, 6, 7])

    y = [9, 1, 8, 4, -2, 8, 6]
    x, r = pava(y, w)
    assert_array_equal(x, [4, 4, 4, 4, 4, 7, 7])
    assert_array_equal(r, [0, 5, 7])

@pytest.mark.parametrize("pava", [pava, gpava_mean])
def test_pava_weighted(pava):
    y = [8, 4, 8, 2, 2, 0, 8]
    w = [1, 2, 3, 4, 5, 5, 4]
    x, r = pava(y, w)
    assert_array_equal(x, [2.9, 2.9, 2.9, 2.9, 2.9, 2.9, 8])
    assert_array_equal(r, [0, 6, 7])

@pytest.mark.parametrize(
    ("y", "fun_lower", "x_lower", "fun_upper", "x_upper"),
    [
        (
            [8, 4, 8, 2, 2, 0, 8],
            median_lower,
            [2, 2, 2, 2, 2, 2, 8],
            median_upper,
            [4, 4, 4, 4, 4, 4, 8],
        ),
        (
            [9, 1, 8, 2, 7, 3, 6],
            median_lower,
            [1, 1, 2, 2, 3, 3, 6],
            median_upper,
            [6, 6, 6, 6, 6, 6, 6],
        ),
        (
            [9, 1, 8, 4, -2, 8, 6],
            median_lower,
            [1, 1, 4, 4, 4, 6, 6],
            median_upper,
            [4, 4, 4, 4, 4, 8, 8],
        ),
        (
            [8, 4, 8, 2, 2, 0, 8],
            quantile80_lower,
            [8, 8, 8, 8, 8, 8, 8],
            quantile80_upper,
            [8, 8, 8, 8, 8, 8, 8],
        ),
        (
            [9, 1, 8, 2, 7, 3, 6],
            quantile80_lower,
            [8, 8, 8, 8, 8, 8, 8],
            quantile80_upper,
            [8, 8, 8, 8, 8, 8, 8],
        ),
        (
            [9, 1, 8, 4, -2, 8, 6],
            quantile80_lower,
            [8, 8, 8, 8, 8, 8, 8],
            quantile80_upper,
            [8, 8, 8, 8, 8, 8, 8],
        ),
        (
            [8, 4, 4, 4, 0, 8, 2, 2, 2, 0, 8],
            median_lower,
            [2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 8],
            median_upper,
            [4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 8],
        ),
        (
            [
                -3.444949308,
                -2.854784791,
                -3.071818855,
                -1.164616209,
                -3.947223934,
                -2.644162705,
                -2.609553073,
                -0.270605801,
                -3.208354459,
                -2.012322283,
                -1.059124491,
                -2.199654113,
                -1.906487545,
                -2.681030502,
                -1.553997732,
                -3.489485619,
                -1.672190775,
                -2.863511214,
                -0.491263988,
                0.169577379,
            ],
            quantile10_lower,
            # from R package isotonic, function
            # gpava(1:20, y, solver = weighted.fractile, p=0.1, ties = "secondary")$x
            np.repeat(
                [-3.947223934, -3.208354459, -2.863511214, -0.491263988, 0.169577379],
                [5, 11, 2, 1, 1],
            ),
            quantile10_upper,
            np.repeat(
                [-3.947223934, -3.208354459, -2.863511214, -0.491263988, 0.169577379],
                [5, 11, 2, 1, 1],
            ),
        ),
    ],
)
def test_gpava_simple(y, fun_lower, x_lower, fun_upper, x_upper):
    w = np.ones_like(y)
    xl, rl = gpava(fun_lower, y, w)
    # The distinction of lower and upper only applies to set-valued functionals like
    # quantiles.
    # Applying gpava on fun=np.quantile(x, level, method="higher") does not work
    # for unknown reasons. What works is to calculate the upper quantile on the
    # block given by rl.
    upper_values = np.fromiter(
        (fun_upper(y[rl[i] : rl[i + 1]]) for i in range(len(rl) - 1)), dtype=xl.dtype
    )
    # Take mininum from the right.
    upper_values = np.minimum.accumulate(upper_values[::-1])[::-1]
    xu = np.repeat(upper_values, np.diff(rl))

    # Check that isotonic_regression gives midpoint.
    functional = fun_lower.loss.functional
    level = getattr(fun_lower.loss, "level", 0.5)
    x_iso, _ = isotonic_regression(y=y, functional=functional, level=level)
    assert_allclose(0.5 * (xl + xu), x_iso)

    for i in range(len(xl) - 1):
        # Eq. 10 of Jordan et al. https://doi.org/10.1007/s10463-021-00808-0
        assert xl[i] <= xu[i + 1]

    # Check manually precomputed values.
    assert_array_equal(xl, x_lower)
    assert_array_equal(xu, x_upper)

    # Check that it is a minimum.
    loss_lower = fun_lower.loss(y_obs=y, y_pred=xl)
    loss_upper = fun_lower.loss(y_obs=y, y_pred=xu)
    assert loss_lower == pytest.approx(loss_upper)

    def objective(y_pred, y_obs):
        return fun_lower.loss(y_obs=y_obs, y_pred=y_pred)

    def constraint(y_pred, y_obs):
        # This is for a monotonically increasing regression.
        return np.diff(y_pred)

    result = minimize(
        fun=objective,
        x0=y,
        args=(y,),
        constraints=[{"type": "ineq", "fun": lambda x: constraint(x, y)}],
        tol=1e-12,
    )

    assert result.fun == pytest.approx(loss_lower, rel=1e-8)

    # Check that it is the boundary of solutions.
    eps = 1e-8 * np.mean(np.abs(xl))
    for i in range(len(xl)):
        x = np.array(xl, copy=True, dtype=float)
        if i == 0 or x[i] > x[i - 1]:
            x[i] -= eps
            assert fun_lower.loss(y_obs=y, y_pred=x) > loss_lower

        x = np.array(xu, copy=True, dtype=float)
        if i == len(xl) - 1 or x[i] < x[i + 1]:
            x[i] += eps
            assert fun_upper.loss(y_obs=y, y_pred=x) > loss_upper

@pytest.mark.parametrize(
    ("functional", "level", "msg"),
    [
        ("no good functional", 0.5, "Argument functional must be one of"),
        ("quantile", 0, "Argument level must fulfil 0 < level < 1"),
        ("quantile", 1, "Argument level must fulfil 0 < level < 1"),
        ("quantile", 1.1, "Argument level must fulfil 0 < level < 1"),
    ],
)
def test_isotonic_regression_raises(functional, level, msg):
    y, w = np.arange(5), np.arange(5)
    with pytest.raises(ValueError, match=msg):
        isotonic_regression(y=y, weights=w, functional=functional, level=level)

@pytest.mark.parametrize("functional", ["quantile", "median"])
def test_isotonic_regression_raises_weighted_quantile(functional):
    y, w = np.arange(5), np.arange(5)
    msg = "Weighted quantile"
    with pytest.raises(NotImplementedError, match=msg):
        isotonic_regression(y=y, weights=w, functional=functional, level=0.5)

@pytest.mark.parametrize(
    ("weights", "msg"),
    [
        ([0, 1, 2], "Input arrays y and w must have one dimension of equal length."),
        ([0, -1], "Weights w must be strictly positive."),
    ],
)
def test_isotonic_regression_raises_weight_array_validation(weights, msg):
    """Test input validation of weight array."""
    y = [0, 1]
    with pytest.raises(ValueError, match=msg):
        isotonic_regression(y=y, weights=weights)

@pytest.mark.parametrize("w", [None, np.ones(7)])
def test_simple_isotonic_regression(w):
    # Test case of Busing 2020
    # https://doi.org/10.18637/jss.v102.c01
    y = np.array([8, 4, 8, 2, 2, 0, 8], dtype=np.float64)
    x, r = isotonic_regression(y, w)
    assert_allclose(x, [4, 4, 4, 4, 4, 4, 8])
    assert_allclose(np.add.reduceat(np.ones_like(y), r[:-1]), [6, 1])
    assert_allclose(r, [0, 6, 7])
    # Assert that y was not overwritten
    assert_array_equal(y, np.array([8, 4, 8, 2, 2, 0, 8], dtype=np.float64))

@pytest.mark.parametrize(
    ("functional", "level", "x_res", "r_res"),
    [
        ("mean", None, [4, 4, 4, 4, 4, 4, 8], [0, 6, 7]),
        ("median", None, [3, 3, 3, 3, 3, 3, 8], [0, 6, 7]),
        ("quantile", 0.5, [3, 3, 3, 3, 3, 3, 8], [0, 6, 7]),
        ("quantile", 0.8, [8, 8, 8, 8, 8, 8, 8], [0, 7]),
        ("expectile", 0.5, [4, 4, 4, 4, 4, 4, 8], [0, 6, 7]),
        ("expectile", 0.8, [6, 6, 6, 6, 6, 6, 8], [0, 6, 7]),
    ],
)
def test_simple_isotonic_regression_functionals(functional, level, x_res, r_res):
    # Test case of Busing 2020
    # https://doi.org/10.18637/jss.v102.c01
    y = np.array([8, 4, 8, 2, 2, 0, 8], dtype=np.float64)
    x, r = isotonic_regression(y, functional=functional, level=level)
    assert_allclose(x, x_res)
    assert_allclose(r, r_res)
    # Assert that y was not overwritten
    assert_array_equal(y, np.array([8, 4, 8, 2, 2, 0, 8], dtype=np.float64))

@pytest.mark.parametrize("increasing", [True, False])
def test_linspace(increasing):
    n = 10
    y = np.linspace(0, 1, n) if increasing else np.linspace(1, 0, n)
    x, r = isotonic_regression(y, increasing=increasing)
    assert_allclose(x, y)
    assert_array_equal(r, np.arange(n + 1))

def test_weights():
    w = np.array([1, 2, 5, 0.5, 0.5, 0.5, 1, 3])
    y = np.array([3, 2, 1, 10, 9, 8, 20, 10])
    x, r = isotonic_regression(y, w)
    assert_allclose(x, [12 / 8, 12 / 8, 12 / 8, 9, 9, 9, 50 / 4, 50 / 4])
    assert_allclose(np.add.reduceat(w, r[:-1]), [8, 1.5, 4])
    assert_array_equal(r, [0, 3, 6, 8])

    # weights are like repeated observations, we repeat the 3rd element 5
    # times.
    w2 = np.array([1, 2, 1, 1, 1, 1, 1, 0.5, 0.5, 0.5, 1, 3])
    y2 = np.array([3, 2, 1, 1, 1, 1, 1, 10, 9, 8, 20, 10])
    x2, r2 = isotonic_regression(y2, w2)
    assert_allclose(np.diff(x2[0:7]), 0)
    assert_allclose(x2[4:], x)
    assert_allclose(np.add.reduceat(w2, r2[:-1]), np.add.reduceat(w, r[:-1]))
    assert_array_equal(r2 - [0, 4, 4, 4], r)

def test_against_R_monotone():
    y = [0, 6, 8, 3, 5, 2, 1, 7, 9, 4]
    x, r = isotonic_regression(y)
    # R code
    # library(monotone)
    # options(digits=8)
    # monotone(c(0, 6, 8, 3, 5, 2, 1, 7, 9, 4))
    res = [
        0,
        4.1666667,
        4.1666667,
        4.1666667,
        4.1666667,
        4.1666667,
        4.1666667,
        6.6666667,
        6.6666667,
        6.6666667,
    ]
    assert_allclose(x, res)
    assert_array_equal(r, [0, 1, 7, 10])

    n = 100
    y = np.linspace(0, 1, num=n, endpoint=False)
    y = 5 * y + np.sin(10 * y)
    x, r = isotonic_regression(y)
    # R code
    # library(monotone)
    # y <- 5 * ((1:n)-1)/n + sin(10 * ((1:n)-1)/n)
    # monotone(y)
    res = [
        0.0000000,
        0.1498334,
        0.2986693,
        0.4455202,
        0.5894183,
        0.7294255,
        0.8646425,
        0.9942177,
        1.1173561,
        1.2333269,
        1.3414710,
        1.4412074,
        1.5320391,
        1.5708110,
        1.5708110,
        1.5708110,
        1.5708110,
        1.5708110,
        1.5708110,
        1.5708110,
        1.5708110,
        1.5708110,
        1.5708110,
        1.5708110,
        1.5708110,
        1.5708110,
        1.5708110,
        1.5708110,
        1.5708110,
        1.5708110,
        1.5708110,
        1.5708110,
        1.5708110,
        1.5708110,
        1.5708110,
        1.5708110,
        1.5708110,
        1.5708110,
        1.5708110,
        1.5708110,
        1.5708110,
        1.5708110,
        1.5708110,
        1.5708110,
        1.5708110,
        1.5708110,
        1.5708110,
        1.5708110,
        1.5708110,
        1.5708110,
        1.5708110,
        1.6241853,
        1.7165453,
        1.8177326,
        1.9272355,
        2.0444597,
        2.1687334,
        2.2993145,
        2.4353978,
        2.5761233,
        2.7205845,
        2.8678375,
        3.0169106,
        3.1668139,
        3.3165492,
        3.4651200,
        3.6115414,
        3.7548499,
        3.8941134,
        4.0284398,
        4.1569866,
        4.2789690,
        4.3936679,
        4.5004366,
        4.5987081,
        4.6880000,
        4.7679197,
        4.8381682,
        4.8656413,
        4.8656413,
        4.8656413,
        4.8656413,
        4.8656413,
        4.8656413,
        4.8656413,
        4.8656413,
        4.8656413,
        4.8656413,
        4.8656413,
        4.8656413,
        4.8656413,
        4.8656413,
        4.8656413,
        4.8656413,
        4.8656413,
        4.8656413,
        4.8656413,
        4.8656413,
        4.8656413,
        4.8656413,
    ]
    assert_allclose(x, res, rtol=2e-7)

    # Test increasing
    assert np.all(np.diff(x) >= 0)

    # Test balance property: sum(y) == sum(x)
    assert_allclose(np.sum(x), np.sum(y))

    # Reverse order
    x, rinv = isotonic_regression(-y, increasing=False)
    assert_allclose(-x, res, rtol=2e-7)
    assert_array_equal(rinv, r)

@pytest.mark.parametrize("increasing", [True, False])
def test_isotonic_regression_class(increasing):
    """Test that IsotonicRegression gives the same as the scikit-learn version."""
    X = [0, 2, 4, -1, -2, 3, 2, 2, 1, 4]
    y = np.arange(10)
    m_skl = skl_IsotonicRegression(increasing=increasing, out_of_bounds="clip").fit(
        X, y
    )
    m = IsotonicRegression(increasing=increasing).fit(X, y)

    assert_allclose(m.X_thresholds_, m_skl.X_thresholds_)
    assert_allclose(m.y_thresholds_, m_skl.y_thresholds_)

    assert m.X_thresholds_[0] == m_skl.X_min_
    assert m.X_thresholds_[-1] == m_skl.X_max_

    X_pred = [-10, -2, 1, 2.5, 10]
    assert_allclose(m.predict(X_pred), m_skl.predict(X_pred))

    m_exp = IsotonicRegression(increasing=increasing, functional="expectile").fit(X, y)
    assert_allclose(m.X_thresholds_, m_exp.X_thresholds_)
    assert_allclose(m.y_thresholds_, m_exp.y_thresholds_)
    assert_allclose(m.predict(X_pred), m_exp.predict(X_pred))

def test_isotonic_regression_class_median():
    """Test IsotonicRegression for median regression."""
    rng = np.random.default_rng(42)
    # Test case of Busing 2020
    # https://doi.org/10.18637/jss.v102.c01
    y = np.array([8, 4, 8, 2, 2, 0, 8], dtype=np.float64)
    y_iso = np.array([3, 3, 3, 3, 3, 3, 8])
    X = np.arange(len(y))
    idx = rng.permutation(X)

    m = IsotonicRegression(functional="quantile", level=0.5).fit(X[idx], y[idx])
    assert_allclose(m.X_thresholds_, [0, 5, 6])
    assert_allclose(m.y_thresholds_, [3, 3, 8])
    assert_allclose(m.predict(X), y_iso)


import os
import shutil
import subprocess
import tempfile
import gevent

from rq import (
    Connection,
    Queue,
)

from utils import (
    all_file_paths_exist,
    copy_or_symlink,
    try_run_command,
    DockerUtils,
    PacmanPackageCache,
    remove
)

from . import (
    RedisHash,
    get_build_object,
    get_pkg_object,
    status,
    get_repo_object
)

logger = status.logger
doc_util = DockerUtils(status)
doc = doc_util.doc

pkg_cache_obj = PacmanPackageCache()

with Connection(status.db):
    repo_queue = Queue('update_repo')

class TransactionMeta(RedisHash):
    """
    This is the base class for `Transaction`(s). It simply sets up the attributes
    which are stored in redis so they can be properly accessed. This class should
    not be used directly.

    Args:
        See `Transaction` docstring.

    Attributes:
        See `Transaction` docstring.
    """

    _main_repo = get_repo_object('antergos', 'x86_64')
    _staging_repo = get_repo_object('antergos-staging', 'x86_64')
    _main_repo32 = get_repo_object('antergos', 'i686')
    _staging_repo32 = get_repo_object('antergos-staging', 'i686')

    attrib_lists = dict(
        string=['building', 'start_str', 'end_str', 'initiated_by', 'gh_sha_before', 'gh_sha_after', 'gh_patch'],
        bool=['is_running', 'is_finished', 'sync_pkgbuilds_only'],
        int=['tnum'],
        list=['queue'],
        set=['packages', 'builds', 'completed', 'failed', 'generated_pkgs'],
        path=['base_path', 'path', 'result_dir', 'cache', 'cache_i686', 'upd_repo_result']
    )

    def __init__(self, packages=None, tnum=None, base_path='/var/tmp/antbs', namespace='antbs',
                 prefix='trans', repo_queue=None):
        if not packages and not tnum:
            raise ValueError('At least one of [packages, tnum] required.')
        elif packages and tnum:
            raise ValueError('Only one of [packages, tnum] can be given, not both.')

        the_tnum = tnum
        if not tnum:
            the_tnum = self.db.incr('antbs:misc:tnum:next')

        super().__init__(namespace=namespace, prefix=prefix, key=the_tnum)

        self.__namespaceinit__()

        self._repo_queue = repo_queue
        self._internal_deps = []
        self._build_dirpaths = {}
        self._pkgvers = {}

        if not self or not self.tnum:
            self.tnum = the_tnum
            self.base_path = base_path
            self.cache = pkg_cache_obj.cache
            self.cache_i686 = pkg_cache_obj.cache_i686

            if packages:
                packages = [p for p in packages if p]

                for pkg in packages:
                    self.packages.add(pkg)

        for pkg in self.packages:
            self._build_dirpaths[pkg] = {'build_dir': '', '32bit': '', '32build': ''}
            self._pkgvers[pkg] = ''

class Transaction(TransactionMeta):
    """
    This class represents a single "build transaction" throughout the app. It is used
    to get/set transaction data from/to the database. A transaction is comprised
    of one or more builds. When a new transaction is initialized it creates its own build
    directory which it will delete once all builds are completed. This allows for
    build concurrency through multiple transactions and can be easily scaled as needed.

        Args:
            packages (list): Names of packages to build. This creates a new `Transaction`.
            tnum (int): Get an existing `Transaction` identified by its `tnum`.

        Attributes:
            tnum (int): This transaction's number or id if you prefer calling it that.
            base_path (str): Absolute path to the top-level build directory (for all transactions).
            path (str): Absolute path to this transaction's build directory.
            builds (list): This transaction's builds (list of bnums)
            is_running (bool): Whether or not the transaction is currently running.
            is_finished (bool): Whether or not the transaction is done (regardless of results)
            building (str): The name of the package currently building.
            start_str (str): The datetime string for when this transaction started.
            end_str (str): The datetime string for when this transaction ended.
            completed (list): Builds that completed successfully (list of bnums).
            failed (list): Builds that failed (list of bnums).
            internal_deps (list): List of packages that depend on package(s) in this transaction.

        Raises:
            ValueError: If both `packages` and `tnum` are Falsey.
    """

    def start(self):
        if self._repo_queue is None:
            logger.debug('self._repo_queue is: %s', self._repo_queue)
            raise AttributeError('_repo_queue is required to start a transaction.')

        status.current_status = 'Initializing build transaction.'
        self.is_running = True

        status.transactions_running.append(self.tnum)
        self.setup_transaction_directory()

        status.current_status = 'Processing packages.'

        self.process_packages()

        if self.sync_pkgbuilds_only:
            return

        status.current_status = 'Cleaning pacman package cache.'

        if len(status.transactions_running) == 1:
            PacmanPackageCache().maybe_do_cache_cleanup()

        while self.queue:
            pkg = self.queue.lpop()
            build_dir = self.get_build_directory(pkg)

            if not build_dir:
                raise RuntimeError('build_dir cannot be None.')

            pkg_obj = get_pkg_object(name=pkg)
            bld_obj = get_build_object(pkg_obj=pkg_obj, tnum=self.tnum, trans_obj=self)

            if pkg_obj.is_iso:
                self.fetch_and_compile_translations(
                    translations_for=["cnchi_updater", "antergos-gfxboot"]
                )
                result = bld_obj.start(pkg_obj)
            else:
                bld_obj = self.setup_build_directory(bld_obj, build_dir)
                result = bld_obj.start(pkg_obj)

            if result in [True, False]:
                blds = pkg_obj.builds
                total = len(blds)

                if total > 0:
                    success = len([x for x in blds if x in status.completed])
                    failure = len([x for x in blds if x in status.failed])

                    if success > 0:
                        success = 100 * success / total

                    if failure > 0:
                        failure = 100 * failure / total

                    pkg_obj.success_rate = success
                    pkg_obj.failure_rate = failure

                if result is True:
                    if not pkg_obj.is_iso:
                        gevent.sleep(2)
                        self.move_files_to_staging_repo(bld_obj)
                        repo_queue.enqueue_call(self._staging_repo.update_repo)
                        repo_queue.enqueue_call(self._staging_repo32.update_repo)
                        gevent.sleep(12)

                    self.completed.append(bld_obj.bnum)
                    doc_util.do_docker_clean(pkg_obj.name)

                elif result is False:
                    self.failed.append(bld_obj.bnum)

            status.now_building.remove(bld_obj.bnum)

        self.is_running = False
        self.is_finished = True
        status.transactions_running.remove(self.tnum)

        remove(self.path)

    def setup_transaction_directory(self):
        path = tempfile.mkdtemp(prefix='{0}_'.format(str(self.tnum)), dir=self.base_path)
        os.chmod(path, 0o777)
        self.result_dir = os.path.join(path, 'result')
        self.upd_repo_result = os.path.join(path, 'upd_result')
        self.path = os.path.join(path, 'antergos-packages', 'antergos')

        os.mkdir(self.result_dir, mode=0o777)
        os.mkdir(self.upd_repo_result, mode=0o777)

        try:
            subprocess.check_output(['/usr/bin/git', 'clone', status.gh_repo_url], cwd=path)
        except subprocess.CalledProcessError as err:
            raise RuntimeError(err.output)

    def get_build_directory(self, pkg):
        pbpath = None
        paths = [
            os.path.join(self.path, 'mate', pkg),
            os.path.join(self.path, 'cinnamon', pkg),
            os.path.join(self.path, 'liri', pkg),
            os.path.join(self.path, pkg)
        ]

        for p in paths:
            if os.path.exists(p):
                pbpath = p
                break
        else:
            raise RuntimeError('Unable to determine pb_path for {0}'.format(pkg))

        return pbpath

    def setup_build_directory(self, bld_obj, build_dir):

        self._build_dirpaths[bld_obj.pkgname].update({
            'build_dir': build_dir,
            '32bit': os.path.join(build_dir, '32bit'),
            '32build': os.path.join(build_dir, '32build'),
            'result': os.path.join(self.result_dir, bld_obj.pkgname)
        })

        for bdir, path in self._build_dirpaths[bld_obj.pkgname].items():
            if not os.path.exists(path):
                os.mkdir(path, mode=0o777)

        bld_obj.build_dir = self._build_dirpaths[bld_obj.pkgname]['build_dir']
        bld_obj._32bit = self._build_dirpaths[bld_obj.pkgname]['32bit']
        bld_obj._32build = self._build_dirpaths[bld_obj.pkgname]['32build']
        bld_obj.result_dir = self._build_dirpaths[bld_obj.pkgname]['result']

        return bld_obj

    def handle_special_cases(self, pkg, pkg_obj):
        if pkg not in ['cnchi-dev', 'cnchi']:
            return

        pkg_obj.prepare_package_source(self.get_build_directory(pkg))

        if 'cnchi' in pkg:
            logger.info('cnchi package detected.')
            status.current_status = 'Fetching latest translations for %s from Transifex.' % pkg
            logger.info(status.current_status)
            self.fetch_and_compile_translations(translations_for=["cnchi"], pkg_obj=pkg_obj)

    @staticmethod
    def move_files_to_staging_repo(bld_obj):
        file_count = len(bld_obj.generated_files)
        files_exist = bld_obj.generated_files and all_file_paths_exist(bld_obj.generated_files)

        if not files_exist or not (file_count % 2 == 0):
            logger.error(
                'Unable to move files to staging repo! files_exist is: %s file_count is: %s',
                files_exist,
                file_count
            )

        for pkg_file in bld_obj.generated_files:
            if 'i686' in pkg_file:
                continue

            fname = os.path.basename(pkg_file)
            staging_file = os.path.join(status.STAGING_64, fname)

            copy_or_symlink(pkg_file, status.STAGING_64, logger)
            bld_obj.staging_files.append(staging_file)

            if '-any.pkg' in pkg_file:
                src = os.path.basename(pkg_file)
                dst = '../i686/{}'.format(fname)

                success, res = try_run_command(
                    ['/bin/ln', '-srf', src, dst],
                    cwd=status.STAGING_64,
                    logger=logger
                )
                if not success:
                    logger.error(res)

        for pkg_file in bld_obj.generated_files:
            if 'x86_64' in pkg_file or '-any.pkg' in pkg_file:
                continue

            fname = os.path.basename(pkg_file)
            staging_file = os.path.join(status.STAGING_32, fname)

            copy_or_symlink(pkg_file, status.STAGING_32, logger)
            bld_obj.staging_files.append(staging_file)

    def process_packages(self):
        _pkgs = [p for p in self.packages if p]

        for pkg in self.packages:
            if not pkg:
                continue

            pbpath = self.get_build_directory(pkg)

            if not pbpath:
                raise RuntimeError('pbpath cannot be None.')

            pkg_obj = get_pkg_object(name=pkg)
            version = pkg_obj.get_version_str()

            if not version and not pkg_obj.is_monitored:
                self.packages.remove(pkg)
                logger.debug('Skipping cnchi-dev build: {0}'.format(pkg))
                continue

            pkg_obj.version_str = version
            self._pkgvers[pkg] = version

            if pkg_obj.is_split_package and pkg_obj.pkgname == pkg_obj.gh_path.rsplit('/')[1]:
                for split_pkg in pkg_obj.split_packages:
                    split_pkg_obj = get_pkg_object(split_pkg)
                    split_pkg_obj.version_str = version
                    split_pkg_obj.pkgver = pkg_obj.pkgver

            log_msg = 'Updating pkgver in database for {0} to {1}'.format(pkg, version)
            logger.info(log_msg)
            status.current_status = log_msg

            depends = pkg_obj.get_deps()

            intersect = list(set(depends) & set(_pkgs))
            logger.debug((depends, intersect))
            if depends and len(intersect) > 0:
                self._internal_deps.append((pkg, intersect))
            else:
                self._internal_deps.append((pkg, []))

            self.handle_special_cases(pkg, pkg_obj)

        status.current_status = 'Using package dependencies to determine build order.'
        if self._internal_deps:
            for name in self.determine_build_order(self._internal_deps):
                if name not in self.queue:
                    self.queue.append(name)

        for pkg in self.packages:
            if pkg not in self.queue:
                self.queue.append(pkg)

    def fetch_and_compile_translations(self, translations_for=None, pkg_obj=None):
        """
        Get and compile translations from Transifex.

        :param (list) translations_for:
        :param (Package) pkg_obj:

        """

        if pkg_obj is None:
            name = ''
        else:
            name = pkg_obj.name or pkg_obj.pkgname

        pbdir = self.get_build_directory(name)
        dest_dir = os.path.join(pbdir, 'po')

        trans = {
            "cnchi": {
                'trans_dir': status.CNCHI_TRANSLATIONS_DIR,
                'trans_files_dir': os.path.join(status.CNCHI_TRANSLATIONS_DIR, '/translations/antergos.cnchi'),
                'dest_dir': dest_dir
            },
            "cnchi_updater": {
                'trans_dir': status.ISO_TRANSLATIONS_DIR,
                'trans_files_dir': os.path.join(status.ISO_TRANSLATIONS_DIR, '/translations/antergos.cnchi_updaterpot'),
                'dest_dir': os.path.join(status.ISO_TRANSLATIONS_DESTDIR, '/cnchi_updater')
            },
            "antergos-gfxboot": {
                'trans_dir': status.ISO_TRANSLATIONS_DIR,
                'trans_files_dir': os.path.join(status.ISO_TRANSLATIONS_DIR, '/translations/antergos.antergos-gfxboot'),
                'dest_dir': os.path.join(status.ISO_TRANSLATIONS_DESTDIR, '/antergos-gfxboot')
            }
        }

        for trans_for in translations_for:

            if not os.path.exists(trans[trans_for]['dest_dir']):
                os.mkdir(trans[trans_for]['dest_dir'])
            try:

                output = subprocess.check_output(['tx', 'pull', '-a', '--minimum-perc=50'],
                                                 cwd=trans[trans_for]['trans_dir'])

                for r, d, f in os.walk(trans[trans_for]['trans_files_dir']):
                    for tfile in f:
                        if trans_for in ['cnchi', 'antergos-gfxboot']:
                            tfile = os.path.join(r, tfile)
                            logger.debug(
                                'Copying %s to %s' % (tfile, trans[trans_for]['dest_dir']))
                            shutil.copy(tfile, trans[trans_for]['dest_dir'])
                        elif 'cnchi_updater' == trans_for:
                            mofile = tfile[:-2] + 'mo'
                            subprocess.check_call(['msgfmt', '-v', tfile, '-o', mofile],
                                                  cwd=trans[trans_for]['trans_files_dir'])
                            os.rename(os.path.join(trans[trans_for]['trans_files_dir'], mofile),
                                      os.path.join(trans[trans_for]['dest_dir'], mofile))

            except subprocess.CalledProcessError as err:
                logger.error(err.output)
            except Exception as err:
                logger.error(err)

    @staticmethod
    def determine_build_order(source):
        """
        Performs a topological sort on elements. This determines the order in which
        packages must be built based on internal (to this transaction) dependencies.

        Args:
            source (list): A list of ``(name, [list of dependancies])`` pairs.

        Returns:
            A list of names, with dependancies listed first.

        Raises:
            ValueError: When cyclic or missing dependancy detected.

        """
        # copy deps so we can modify set in-place
        pending = [(name, set(deps)) for name, deps in source]
        emitted = []
        try:
            while pending:
                next_pending = []
                next_emitted = []

                for entry in pending:
                    name, deps = entry
                    # remove deps we emitted last pass
                    deps.difference_update(emitted)

                    if deps:
                        # still has deps? recheck during next pass
                        next_pending.append(entry)
                    else:
                        # no more deps? time to emit
                        yield name
                        emitted.append(name)
                        # remember what we emitted for difference_update() in next pass
                        next_emitted.append(name)

                if not next_emitted:
                    # all entries have unmet deps, one of two things is wrong...
                    logger.error('cyclic or missing dependancy detected: %r', next_pending)
                    names = [n for n, d in source]
                    deps = [d for n, d in source]
                    missing = [m for d in deps for m in d if m not in names]
                    logger.error(names)
                    logger.error(deps)
                    logger.error(missing)

                    raise ValueError
                pending = next_pending
                emitted = next_emitted
        except ValueError as err:
            logger.error(err)

def get_trans_object(packages=None, tnum=None, repo_queue=None):
    """
    Gets an existing transaction or creates a new one.

    Args:
        packages (list): Create a new transaction with these packages.
        tnum (int): Get an existing transaction identified by `tnum`.

    Returns:
        Transaction: A fully initiallized `Transaction` object.

    Raises:
        ValueError: If both `packages` and `tnum` are Falsey or Truthy.

    """
    if not any([packages, tnum]):
        raise ValueError('At least one of [packages, tnum] required.')
    elif all([packages, tnum]):
        raise ValueError('Only one of [packages, tnum] can be given, not both.')

    trans_obj = Transaction(packages=packages, tnum=tnum, repo_queue=repo_queue)

    return trans_obj


# importing the modules
import numpy as np
import matplotlib.pyplot as plt

# data to be plotted
x = np.arange(1, 11)
print(x)

y = x * x
print(y)

# plotting
plt.title("Line graph")

plt.xlabel("X axis")
plt.ylabel("Y axis")

plt.plot(x, y, color="red")
plt.show()