code:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

"""
    Inary Package Signing Tools
"""

import base64
import getpass
import io
import os
import hashlib
import shlex
import shutil
import subprocess
import sys
import tempfile
import zipfile

# ZipFile extensions
ZIP_FILES = ('.zip', '.inary')

# Signature headers & extensions
HEADER = 'inary-signed'
EXT_SIGN = 'sig'
EXT_CERT = 'crt'

# Signature validity
SIGN_OK, SIGN_NO, SIGN_SELF, SIGN_UNTRUSTED, SIGN_CORRUPTED = list(range(5))

# Certificate validity
CERT_OK, CERT_SELF, CERT_CORRUPTED = list(range(3))

# Certificate trustworthiness
CERT_TRUSTED, CERT_UNTRUSTED = list(range(2))

def sign_data(data, key_file, password_fd):
    """
        Signs data with given key.

        Arguments:
            data: Data to be signed
            key_file: Private key
            password_fd: File that contains passphrase
        Returns:
            Signed data (binary)
    """
    # Go to begining of password file
    password_fd.seek(0)
    # Use OpenSSL to sign data
    command = '/usr/bin/openssl dgst -sha1 -sign {} -passin file:{}'
    command = command.format(key_file, password_fd.name)

    command = shlex.split(command)

    pipe = subprocess.Popen(command, stdin=subprocess.PIPE,
                                     stdout=subprocess.PIPE,
                                     stderr=subprocess.PIPE)

    pipe.stdin.write(data.encode("utf-8"))
    pipe.stdin.close()
    # Get signed data
    signed_binary = pipe.stdout.read()
    print(pipe.stderr.read())
    return signed_binary

def get_public_key(cert_file):
    """
        Extracts public key from certificate.

        Arguments:
            cert_file: Certificate
        Returns:
            Public key
    """
    # Use OpenSSL to extract public key
    command = 'openssl x509 -inform pem -in {} -pubkey -noout'
    command = command.format(cert_file)
    command = shlex.split(command)

    pipe = subprocess.Popen(command, stdout=subprocess.PIPE,
                                     stderr=subprocess.PIPE)
    key_ascii = pipe.stdout.read()

    return key_ascii

def get_hash(cert_file):
    """
        Extracts hash from certificate.

        Arguments:
            cert_file: Certificate
        Returns:
            Hash
    """
    # Use OpenSSL to extract hash
    command = 'openssl x509 -noout -in {} -hash'
    command = command.format(cert_file)
    command = shlex.split(command)

    pipe = subprocess.Popen(command, stdout=subprocess.PIPE,
                                     stderr=subprocess.PIPE)
    hash = pipe.stdout.read()
    hash = hash.strip()

    return hash

def check_trust(cert_file, trust_dir):
    """
        Checks if certificate is trusted or not.

        Arguments:
            cert_file: Certificate
            trust_dir: Path to trust database.
        Returns:
            CERT_TRUSTED or CERT_UNTRUSTED
    """

    cert_hash = get_hash(cert_file)

    for filename in os.listdir(trust_dir):
        cert_path = os.path.join(trust_dir, filename)
        if os.path.exists(cert_path):
            if cert_hash == get_hash(cert_path):
                return CERT_TRUSTED
    return CERT_UNTRUSTED

    """
    # Code to be used in production:
    cert_hash = get_hash(cert_file)
    cert_path = os.path.join(trust_dir, cert_hash)
    if os.path.exists(cert_path):
        if cert_hash == get_hash(cert_path):
            return CERT_TRUSTED
    return CERT_UNTRUSTED
    """

def verify_certificate(cert_file):
    """
        Verifies a certificate.

        Arguments:
            cert_file: Certificate
        Returns:
            CERT_OK, CERT_SELF or CERT_CORRUPTED
    """
    # Use OpenSSL to verify certificate
    command = '/usr/bin/openssl verify {}'
    command = command.format(cert_file)
    command = shlex.split(command)

    pipe = subprocess.Popen(command, stdout=subprocess.PIPE,
                                     stderr=subprocess.PIPE)

    lines = pipe.stdout.read().decode("utf-8").split('\n')

    if len(lines) < 2:
        return CERT_CORRUPTED
    elif lines[1].startswith("error"):
        code = lines[1].split()[1]
        if code == '18':
            return CERT_SELF
        else:
            return CERT_CORRUPTED
    else:
        return CERT_OK

def verify_file(data_file, cert_file=None, signature_file=None, trust_dir=None):
    """
        Verifies signature of file signed with given certificate.

        If signature_file is not defined data_file + ".sig" will
        be used.

        If cert_file is not defined data_file + ".crt" will
        be used.

        Arguments:
            data_file: Original data file
            cert_file: Certificate (or None)
            signature_file: Signature file (or None)
            trust_dir: Path to trust database.
        Returns:
            SIGN_OK, SIGN_NO, SIGN_SELF or SIGN_CORRUPTED
    """
    # Sanitize before appending signature extension
    data_file = os.path.realpath(data_file)

    if not signature_file:
        signature_file = data_file + '.' + EXT_SIGN
    if not cert_file:
        cert_file = data_file + '.' + EXT_CERT
    if not os.path.exists(signature_file) or not os.path.exists(cert_file):
        return SIGN_NO

    # Verify certificate
    cert_validity = verify_certificate(cert_file)
    if cert_validity == CERT_CORRUPTED:
        return SIGN_CORRUPTED

    # Check trustworthiness of certificate
    if trust_dir != None and check_trust(cert_file, trust_dir) == CERT_UNTRUSTED:
        return SIGN_UNTRUSTED

    # Keep public key in a temporary file
    pub_file = tempfile.NamedTemporaryFile()
    pub_file.write(get_public_key(cert_file))
    pub_file.flush()

    # Use OpenSSL to verify signature
    command = '/usr/bin/openssl dgst -sha1 -verify {} -signature {} {}'
    command = command.format(pub_file.name, signature_file, data_file)
    command = shlex.split(command)

    pipe = subprocess.Popen(command, stdout=subprocess.PIPE,
                                     stderr=subprocess.PIPE)
    result = pipe.wait()
    # Destroy temporary files
    pub_file.close()

    if result == 0:
        if cert_validity == CERT_OK:
            return SIGN_OK
        else:
            return SIGN_SELF
    else:
        return SIGN_CORRUPTED

def verify_data(data, signature_data, trust_dir):
    """
        Verifies signature of data signed with given certificate.

        Arguments:
            data: Original data
            signature_data: Signature data from ZipFile
            trust_dir: Path to trust database.
        Returns:
            SIGN_OK, SIGN_NO, SIGN_SELF or SIGN_CORRUPTED
    """
    # Check header
    if isinstance(type(signature_data), type(bytes)):
        signature_data=signature_data.decode("utf-8")
    if not len(signature_data) or not signature_data.startswith(HEADER):
        return SIGN_NO
    else:
        try:
            header, cert_ascii, signature_ascii = signature_data.split(':')
        except ValueError:
            return SIGN_CORRUPTED
        if header != HEADER:
            return SIGN_CORRUPTED
        signature_binary = base64.b64decode(signature_ascii)
        cert_data = base64.b64decode(cert_ascii)

    # Keep certificate in a temporary file
    cert_file = tempfile.NamedTemporaryFile()
    cert_file.write(cert_data)
    cert_file.flush()

    # Keep signature in a temporary file
    signature_file = tempfile.NamedTemporaryFile()
    signature_file.write(signature_binary)
    signature_file.flush()

    # Keep data in a temporary file
    data_file = tempfile.NamedTemporaryFile()
    data_file.write(data.encode("utf-8"))
    data_file.flush()

    # Verify
    result = verify_file(data_file.name, cert_file.name, signature_file.name, trust_dir)

    # Destroy temporary files
    cert_file.close()
    signature_file.close()
    data_file.close()

    return result

def get_zip_hashes(zip_obj):
    """
        Calculates content hashes of a ZIP file.

        Example hash content:
            dir/file1 9971487c1c7ec8afbf4617460244ce4b9e11a867
            dir/file2 0b3e42702ef1c5190590534d0b3ee6c7fb45b0c6
            file3 7053bd69a3ba35cbcd2a635a090ec5f2cd439e29

        Arguments:
            zip_obj: ZipFile object
        Returns:
            ZIP content hashes
    """
    hashes = []

    for info in zip_obj.infolist():
        content = zip_obj.read(info.filename)
        content_hash = hashlib.sha1(content).hexdigest()
        hashes.append('{} {}'.format(info.filename, content_hash))

    return "\n".join(hashes)

def verify_zipfile(filename, trust_dir=None):
    """
        Verifies integrity of a ZIP file.

        Arguments:
            filename: ZIP filename
            trust_dir: Path to trust database.
        Returns:
            SIGNED, UNSIGNED, SELF_SIGNED or CORRUPTED
    """

    try:
        zip_obj = zipfile.ZipFile(filename)
    except (IOError, zipfile.BadZipfile):
        return False

    # Get ZIP hashes
    hashes = get_zip_hashes(zip_obj)

    # Read signed hash data from ZIP comment
    signature_data = zip_obj.comment

    # Close ZIP file
    zip_obj.close()

    # Verify signed data
    return verify_data(hashes, signature_data, trust_dir)

def sign_file(filename, key_file, cert_file, password_fd):
    """
        Signs file with given key.

        Arguments:
            filename: File name to be signed
            key_file: Private key
            cert_file: Certificate
            password_fd: File that contains passphrase
    """
    data = open(filename).read()
    signed_binary = sign_data(data, key_file, password_fd)
    cert_data = open(cert_file,"rb").read()

    # Save certificate
    open('{}.{}'.format(filename, EXT_CERT), 'wb').write(cert_data)

    # Save signed data
    open('{}.{}'.format(filename, EXT_SIGN), 'wb').write(signed_binary)

def sign_zipfile(filename, key_file, cert_file, password_fd):
    """
        Signs ZIP file with given key.

        Arguments:
            filename: File name to be signed
            key_file: Private key
            cert_file: Certificate
            password_fd: File that contains passphrase
    """
    zip_obj = zipfile.ZipFile(filename, 'a')

    # Get ZIP hashes and sign them
    hashes = get_zip_hashes(zip_obj)
    signed_binary = sign_data(hashes, key_file, password_fd)
    signed_ascii = base64.b64encode(signed_binary)

    # Encode certificate
    cert_data = open(cert_file, "rb").read()
    cert_ascii = base64.b64encode(cert_data)

    # Add signed data as ZIP comment
    zip_obj.comment = HEADER.encode("utf-8") + b":" + cert_ascii + b":" + signed_ascii

    # Mark file as modified and save it
    zip_obj._didModify = True
    zip_obj.close()

def print_usage():
    """
        Prints usage information of application and exits.
    """

    print("Usage:")
    print("  {} sign <priv_key> <cert> <file1 ...>".format(sys.argv[0]))
    print("  {} verify <trust_dir> <file1 ...>".format(sys.argv[0]))
    print("  {} generate_certs <cert_dir> <trusted ...>".format(sys.argv[0]))
    sys.exit(1)

def main():
    """
        Main
    """

    try:
        operation = sys.argv[1]
    except IndexError:
        print_usage()

    if operation == 'sign':
        try:
            key_file = sys.argv[2]
            cert_file = sys.argv[3]
        except IndexError:
            print_usage()

        if len(sys.argv[4:]):
            # Keep password in a temporary file
            password = getpass.getpass()
            temporary_name = tempfile.mkstemp()[1]

            with open(temporary_name, mode="a+") as password_fd:
                password_fd.write(password)
                password_fd.flush()

                for filename in sys.argv[4:]:
                    if filename.endswith(ZIP_FILES):
                        sign_zipfile(filename, key_file, cert_file, password_fd)
                    else:
                        sign_file(filename, key_file, cert_file, password_fd)
                    print("Signed {} with {}".format(filename, key_file))

                os.remove(temporary_name)

        else:
            print_usage()

    elif operation == 'verify':
        try:
            trust_dir = sys.argv[2]
        except IndexError:
            print_usage()

        if len(sys.argv[3:]):
            for filename in sys.argv[3:]:
                if filename.endswith(ZIP_FILES):
                    result = verify_zipfile(filename, trust_dir)
                else:
                    result = verify_file(filename, trust_dir=trust_dir)
                if result == SIGN_OK:
                    print("{} is signed by a trusted source.".format(filename))
                elif result == SIGN_NO:
                    print("{} is unsigned.".format(filename))
                elif result == SIGN_SELF:
                    print("{} is self-signed by a trusted source.".format(filename))
                elif result == SIGN_UNTRUSTED:
                    print("{} is signed by an untrusted source.".format(filename))
                else:
                    print("{} is corrupted.".format(filename))
        else:
            print_usage()
    elif operation == 'generate_certs':
        if len(sys.argv[3:]):
            print("Generating certificates...")
            print("Creating certificate directory: {}".format(sys.argv[2]))
            if not os.path.exists(sys.argv[2]): os.makedirs(sys.argv[2])
            print("Creating trusted certificate directory: {}".format(sys.argv[3]))
            if not os.path.exists(sys.argv[3]): os.makedirs(sys.argv[3])

            temporary_name = tempfile.mkstemp()[1]

            with open(temporary_name, mode="a+") as password_fd:
                password=getpass.getpass()
                password_fd.write(password)
                password_fd.flush()

                os.system("/usr/bin/openssl genrsa -des3 -out {0}/enc_key.pem 1024".format(sys.argv[2]))

                os.system("/usr/bin/openssl req -new -subj '/C=TR/ST=Sivas/L=Merkez/CN=Sulin' -key {0}/enc_key.pem -out {0}/req.pem -passin file:{1}".format(sys.argv[2], temporary_name))
                os.system("/usr/bin/openssl req -x509 -key {0}/enc_key.pem -in {0}/req.pem -out {0}/cert.pem -days 365 -passin file:{1}".format(sys.argv[2], temporary_name))
                shutil.copy("{}/cert.pem".format(sys.argv[2]), sys.argv[3])
                os.remove(temporary_name)
        else:
            print_usage()

    else:
        print_usage()

if __name__ == "__main__":
    sys.exit(main())


code:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#
# Copyright (C) 2018, Suleyman POYRAZ (Zaryob)
#
# This program is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the
# Free Software Foundation; either version 2 of the License, or (at your
# option) any later version. Please read the COPYING file.

import os
import re
import sys
import xml.dom.minidom as dom

po_header_tmpl = """# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\\n"
"Report-Msgid-Bugs-To: \\n"
"POT-Creation-Date: 2018-01-01 12:58+0200\\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n"
"Language-Team: LANGUAGE <LL@li.org>\\n"
"MIME-Version: 1.0\\n"
"Content-Type: text/plain; charset=UTF-8\\n"
"Content-Transfer-Encoding: 8bit\\n"
"""

class Message:
    def __init__(self):
        self.reference = None
        self.flags = []
        self.msgid = None
        self.msgstr = None

class Po:
    def __init__(self, messages = None, header = None):
        self.messages = messages or []
        self.header = header or po_header_tmpl

    def _escape(self, str):
        if not str:
            return '""'

        str = re.sub('"', '\\"', str)

        parts = str.split("\n")

        if len(parts) == 1:
            return '"{}"'.format(parts[0])

        if str.endswith("\n"):
            parts = parts[:-1]

        ret = '""' + "".join(map(lambda x: '\n"{}\\n"'.format(x), parts))

        return ret

    def save(self, filename):
        f = open(filename, "w")
        f.write(self.header)
        for msg in self.messages:
            po_entry = "\n#: {}\n".format(msg.reference)
            if msg.flags:
                po_entry += "#, " + ", ".join(msg.flags) + "\n"
            po_entry += "msgid {}\n".format(self._escape(msg.msgid))
            po_entry += "msgstr {}\n".format(self._escape(msg.msgstr))
            f.write(po_entry)
        f.close()

    def _unescape(self, str):
        str = re.sub('\\\\"', '"', str)
        str = re.sub('\\\\n', '\n', str)
        return str

    def load(self, filename):
        sHeader, sSkip, sComment, sId, sMsg = range(5)
        self.messages = []
        self.header = ""
        msg = None
        state = sHeader
        # Silly state machines are easier to code than dealing with regexps
        for line in open(filename):
            line = line.rstrip("\n")

            if state == sHeader:
                if len(line.split()) == 0:
                    state = sSkip
                else:
                    self.header += line + "\n"
                continue

            if state == sSkip:
                if len(line.split()) != 0:
                    msg = Message()
                    state = sComment
                else:
                    continue

            if state == sComment:
                if line.startswith("#: "):
                    msg.reference = line[3:]
                    continue
                elif line.startswith("#, "):
                    msg.flags = line[3:].split(',')
                    continue
                elif line.startswith("msgid "):
                    state = sId
                else:
                    continue

            if state == sId:
                if line.startswith("msgstr "):
                    state = sMsg
                else:
                    if line == 'msgid ""':
                        continue
                    if not msg.msgid:
                        msg.msgid = ""
                    msg.msgid += line[line.find('"')+1:line.rfind('"')]

            if state == sMsg:
                if len(line.split()) == 0:
                    msg.msgid = self._unescape(msg.msgid)
                    msg.msgstr = self._unescape(msg.msgstr)
                    self.messages.append(msg)
                    state = sSkip
                else:
                    if not msg.msgstr:
                        msg.msgstr = ""
                    if line == 'msgstr ""':
                        continue
                    msg.msgstr += line[line.find('"')+1:line.rfind('"')]

        if msg:
            msg.msgid = self._unescape(msg.msgid)
            msg.msgstr = self._unescape(msg.msgstr)
            self.messages.append(msg)

def find_packages(path):
    paks = []
    for root, dirs, files in os.walk(path):
        if "pspec.xml" in files:
            paks.append(root)
        # dont walk into the versioned stuff
        if ".svn" in dirs:
            dirs.remove(".svn")
    return paks

def getDataByTagName(elem, tag):
    try:
        return elem.getElementsByTagName(tag)[0].firstChild.data
    except:
        pass

def extract_from_translationsxmls(path, language, old_messages = []):
    if not path.endswith('/'):
        path += '/'
    messages = []
    paks = find_packages(path)

    # For duplicate msgid detection
    old_msg_ids = [omsg.msgid for omsg in old_messages]
    print("Number of old translations: {}".format(len(old_msg_ids)))

    def strp(msg):
        if msg:
            return msg.strip()
        return ""

    def set_fuzzy_flag(msg):
        for old_msg in old_messages:
            if old_msg.reference == msg.reference:
                if len(old_msg.msgstr) and old_msg.msgstr == msg.msgstr:
                    if ('fuzzy' in old_msg.flags) or (strp(old_msg.msgid) != strp(msg.msgid)):
                        msg.flags.append("fuzzy")
                if (old_msg.msgid == msg.msgid) and (strp(old_msg.msgstr) != strp(msg.msgstr)):
                        msg.msgstr = old_msg.msgstr
        return msg

    def get_translation(pak, section, tag, name):
        if not os.path.exists(pak + "/translations.xml"):
            return ""
        try:
            translations = dom.parse(pak + "/translations.xml")
            for t_node in translations.getElementsByTagName(section):
                if getDataByTagName(t_node, "Name") == name:
                    for t_item in t_node.getElementsByTagName(tag):
                        t_lang = t_item.getAttribute("xml:lang")
                        if t_lang == language:
                            return t_item.firstChild.data
                    return ""
        except:
            print("* Failed parsing {}/translations.xml".format(pak))

    # function starts here.
    paklen = 0
    msgidlen = 0

    for pak in paks:
        paklen += 1
        spec = None
        try:
            spec = dom.parse(pak + "/pspec.xml")
        except:
            print("* Failed parsing {}/pspec.xml".format(pak))
            continue

        for section in ["Package", "Source"]:
            for node in spec.getElementsByTagName(section):
                for tag in ["Summary", "Description"]:
                    msg = Message()
                    for item in node.getElementsByTagName(tag):
                        lang = item.getAttribute("xml:lang")
                        if not lang or lang == "en":
                            msgidlen += 1
                            msg.msgid = item.firstChild.data
                        msg.msgstr = get_translation(pak, section, tag, getDataByTagName(node, "Name"))

                        if section == "Package":
                            msg.reference = pak[len(path):] + ":" + getDataByTagName(node, "Name") + ":" + tag.lower()
                        else:
                            msg.reference = pak[len(path):] + "::" + tag.lower()

                    if msg.msgid and (msg.msgid not in old_msg_ids):
                        msg = set_fuzzy_flag(msg)
                        messages.append(msg)
                        old_msg_ids.append(msg.msgid)

    print("packages: {0}, msgids: {1}".format(paklen, msgidlen))
    return messages

def update_translationsxmls(path, language, po):

    finished_packages = []

    def get_sourcepackage(type, name):
        source_node = Element(type)
        name_node = Element("Name")
        name_txt = Text(name)
        name_node.appendChild(name_txt)
        source_node.appendChild(name_node)
        return source_node

    def get_sumdesc(type, content):
        node = Element(type)
        node.setAttribute("xml:lang", language)
        cnt = Text(content)
        node.appendChild(cnt)
        return node

    def has_item(doc, item, package_name):
        if len(doc.getElementsByTagName(item)) == 0:
            return False
        for i in doc.getElementsByTagName(item):
            if getDataByTagName(i, "Name") == package_name:
                return True
        return False

    def has_lang(item, tag, language):
        for s in item.getElementsByTagName(tag):
            if s.getAttribute("xml:lang") == language:
                return True
        return False

    Element = lambda x: dom.Document().createElement(x)
    Text = lambda x: dom.Document().createTextNode(x)

    for msg in po.messages:
        if not msg.msgstr:
            continue
        if "fuzzy" in msg.flags:
            continue

        current_name, type_flag, tag = msg.reference.split(':')
        tag = tag.title()

        if not os.path.exists(os.path.join(path, current_name)):
            #package may be removed to another place or deleted from repository..
            continue

        if current_name in finished_packages:
            continue
        else:
            finished_packages.append(current_name)

        translations = os.path.join(path, current_name, "translations.xml")
        if os.path.exists(translations):
            doc = dom.parse(translations)
            inary = doc.getElementsByTagName("INARY")[0]
        else:
            doc = dom.Document()
            inary = Element("INARY")

        for msg in po.messages:
            if not msg.msgstr:
                continue
            if "fuzzy" in msg.flags:
                continue

            name, type_flag, tag = msg.reference.split(':')
            tag = tag.title()

            if name != current_name:
                continue

            if not type_flag:
                item = "Source"
                package_name = os.path.basename(name)
            else:
                item = "Package"
                package_name = type_flag

            if os.path.exists(translations):
                # if not, we need to create one, with fabricated content
                if has_item(doc, item, package_name):
                    # if not, it means there is no entry for 'item' in translations.xml
                    # we're gonna need to create that entry first
                    for i in doc.getElementsByTagName(item):
                        if getDataByTagName(i, "Name") == package_name:
                            if has_lang(i, tag, language):
                                # if not, it means we have item with the correct package
                                # name, but we need to insert a new 'tag' into the item node
                                # with the correct language attribute instead of changing
                                # the existing one.
                                for s in i.getElementsByTagName(tag):
                                    if s.getAttribute("xml:lang") == language:
                                        s.firstChild.data = msg.msgstr
                            else:
                                sumdesc = get_sumdesc(tag, msg.msgstr)
                                i.appendChild(sumdesc)
                else:
                    entry = get_sourcepackage(item, package_name)
                    sumdesc = get_sumdesc(tag, msg.msgstr)
                    entry.appendChild(sumdesc)
                    inary.appendChild(entry)
            else:
                entry = get_sourcepackage(item, package_name)
                sumdesc = get_sumdesc(tag, msg.msgstr)
                entry.appendChild(sumdesc)
                inary.appendChild(entry)
                doc.appendChild(inary)

        # we can't use .toprettyxml() here. Because it also adds newlines and tabs
        # before and after of sum/desc data. Result looks like this:
        #
        # (...)
        # <Description xml:lang="mi">
        #     Lorem ipsum dolor sit amet..
        # </Description>
        # (...)
        #
        # and we don't want that.
        xml = doc.toxml()
        xml = xml.replace("\n    <", "<")
        xml = xml.replace("\n\n    <", "<")
        xml = xml.replace("\n        <", "<")
        xml = xml.replace("\n        <", "<")
        xml = xml.replace("\n<", "<")
        xml = xml.replace("\n\n<", "<")
        xml = xml.replace("<INARY>", "\n<INARY>")
        xml = xml.replace("</INARY>", "\n</INARY>")
        xml = xml.replace("<Source>", "\n    <Source>")
        xml = xml.replace("<Package>", "\n\n    <Package>")
        xml = xml.replace("</Source>", "\n    </Source>")
        xml = xml.replace("</Package>", "\n    </Package>")
        xml = xml.replace("<Name>", "\n        <Name>")
        xml = xml.replace("<Description ", "\n        <Description ")
        xml = xml.replace("<Summary ", "\n        <Summary ")
        if xml[-1] != "\n":
            xml += "\n"
        open(translations, "w").write(xml)

    print("{} translations have been translated.".format(len(finished_packages)))

def extract(path, language, pofile):
    if os.path.exists(pofile):
        old_po = Po()
        old_po.load(pofile)
        po = Po(header = old_po.header)
        po.messages = extract_from_translationsxmls(path, language, old_po.messages)
        po.save(pofile)
    else:
        po = Po()
        po.messages = extract_from_translationsxmls(path, language)
        po.save(pofile)

def update(path, language, pofile):
    po = Po()
    po.load(pofile)
    update_translationsxmls(path, language, po)

def usage():
        print("Extract translatable strings into a po file:")
        print("  pspec2po extract repopath language output_po_file")
        print("Update pspec translations from a po file:")
        print("  pspec2po update repopath language input_po_file")

if __name__ == "__main__":
    if len(sys.argv) == 1 or sys.argv[1] == "help":
        usage()

    elif len(sys.argv) == 5 and sys.argv[1] == "extract":
        extract(sys.argv[2], sys.argv[3], sys.argv[4])

    elif len(sys.argv) == 5 and sys.argv[1] == "update":
        update(sys.argv[2], sys.argv[3], sys.argv[4])

    else:
        usage()

repo_name: SulinOS/inary

license: mit


code:
#!/bin/bash

# revdep-rebuild: Reverse dependency rebuilder.
# Author: Stanislav Brabec <utx@gentoo.org>

# Adapt to Pardus
# Author: Ozan Caglayan <ozan@pardus.org.tr>

# Adapt to Sulin
# Author: Suleyman Poyraz <zaryob.dev@gmail.com>

# Mask of specially evaluated libraries (exactly one space separated).
LD_LIBRARY_MASK="libodbcinst.so libodbc.so libjava.so libjvm.so"

# List of directories to be searched (feel free to edit it)
# Note /usr/libexec and /usr/local/subprefix contradicts FHS, but are present
SEARCH_DIRS="/lib /bin /sbin /usr/lib /usr/bin /usr/sbin /usr/libexec /usr/local /usr/qt* /usr/kde/*/bin /usr/lib/MozillaFirefox /usr/kde/*/lib /usr/*-*-linux-gnu /opt"
EXCLUDE_DIRS="/opt/ptsp /usr/lib/xorg/nvidia* /usr/lib/debug"

# Base of temporary files names.
LIST=~/.revdep-rebuild

shopt -s nullglob
shopt -s expand_aliases
unalias -a

NO="\x1b[0;0m"
BR="\x1b[0;01m"
CY="\x1b[36;01m"
GR="\x1b[32;01m"
RD="\x1b[31;01m"
YL="\x1b[33;01m"
BL="\x1b[34;01m"

alias echo_v=echo

SONAME="not found"
SONAME_GREP=fgrep
SEARCH_BROKEN=true

while : ; do
	case "$1" in
	-h | --help )
		echo "Usage: $0 [OPTIONS] [--]"
		echo
		echo "Broken reverse dependency checker."
		echo
		echo
        echo "      --force          remove old revdep-rebuild files"
		echo
		echo "      --soname SONAME  recompile packages using library with SONAME instead"
		echo "                       of broken library (SONAME providing library must be"
		echo "                       present in the system)"
		echo "      --soname-regexp SONAME"
		echo "                       the same as --soname, but accepts grep-style regexp"
		echo "  -q, --quiet          be less verbose"
		echo
		exit 0
		;;
	-q | --quiet )
		alias echo_v=:
		shift
		;;
	--soname=* )
		SONAME="${1#*=}"
		SEARCH_BROKEN=false
		shift
		;;
	--soname )
		SONAME="$2"
		SEARCH_BROKEN=false
		shift 2
		;;
	--soname-regexp=* )
		SONAME="${1#*=}"
		SONAME_GREP=grep
		SEARCH_BROKEN=false
		shift
		;;
	--soname-regexp )
		SONAME="$2"
		SONAME_GREP=grep
		SEARCH_BROKEN=false
		shift 2
		;;
	--force )
		FORCE=true
		shift
		;;
	-- )
		shift
		break
		;;
	* )
		break
		;;
	esac
done

function set_trap () {
	trap "rm_temp $1" SIGHUP SIGINT SIGQUIT SIGABRT SIGTERM
}

function rm_temp () {
	echo " terminated."
	echo "Removing incomplete $1."
	rm $1
	echo
	exit 1
}

if $FORCE ; then
	rm -f /root/.revdep-rebuild*
fi

if $SEARCH_BROKEN ; then
	SONAME_SEARCH="$SONAME"
	LLIST=$LIST
	HEAD_TEXT="broken by any package update"
	OK_TEXT="Dynamic linking on your system is consistent"
	WORKING_TEXT=" consistency"
else
	SONAME_SEARCH="	$SONAME "
	LLIST=${LIST}_$(echo "$SONAME_SEARCH$SONAME" | md5sum | head -c 8)
	HEAD_TEXT="using given shared object name"
	OK_TEXT="There are no dynamic links to $SONAME"
	WORKING_TEXT=""
fi

echo
echo "Checking reverse dependencies..."

echo
echo -n -e "${GR}Collecting system binaries and libraries...${NO}"
if [ -f $LIST.1_files ] ; then
	echo " using existing $LIST.1_files."
else
	set_trap "$LIST.1_files"
    EXCLUDED_DIRS=
    for d in $EXCLUDE_DIRS; do
        EXCLUDED_DIRS+="-path $d -prune -o "
    done
	find $SEARCH_DIRS $EXCLUDED_DIRS -type f \( -perm /+u+x -o -name '*.so' -o -name '*.so.*' \) 2>/dev/null >$LIST.1_files
	echo -e " done.\n  ($LIST.1_files)"
fi

if $SEARCH_BROKEN ; then
	echo
	echo -n -e "${GR}Collecting complete LD_LIBRARY_PATH...${NO}"
	if [ -f $LIST.2_ldpath ] ; then
	echo " using existing $LIST.2_ldpath."
	else
	set_trap "$LIST.2_ldpath"
	(
		grep '.*\.so\(\|\..*\)$' <$LIST.1_files | sed 's:/[^/]*$::'
		sed '/^#/d;s/#.*$//' </etc/ld.so.conf
	) | sort -u |
	tr '\n' : | tr -d '\r' | sed 's/:$//' >$LIST.2_ldpath
	echo -e " done.\n  ($LIST.2_ldpath)"
	fi
	export COMPLETE_LD_LIBRARY_PATH="$(cat $LIST.2_ldpath)"
fi

echo
echo -n -e "${GR}Checking dynamic linking$WORKING_TEXT...${NO}"
if [ -f $LLIST.3_rebuild ] ; then
	echo " using existing $LLIST.3_rebuild."
else
	echo_v
	set_trap "$LLIST.3_rebuild"
	LD_MASK="\\(	$(echo "$LD_LIBRARY_MASK" | sed 's/\./\\./g;s/ / \\|	/g') \\)"
	echo -n >$LLIST.3_rebuild
	cat $LIST.1_files | while read FILE ; do
	# Note: double checking seems to be faster than single
	# with complete path (special add ons are rare).
	if ldd "$FILE" 2>/dev/null | grep -v "$LD_MASK" |
		$SONAME_GREP -q "$SONAME_SEARCH" ; then
		if $SEARCH_BROKEN ; then
		if LD_LIBRARY_PATH="$COMPLETE_LD_LIBRARY_PATH" \
		ldd "$FILE" 2>/dev/null | grep -v "$LD_MASK" |
			$SONAME_GREP -q "$SONAME_SEARCH" ; then
			echo "$FILE" >>$LLIST.3_rebuild
			echo_v "  broken $FILE (requires $(ldd "$FILE" | sed -n 's/	\(.*\) => not found$/\1/p' | tr '\n' ' ' | sed 's/ $//' ))"
		fi
		else
		echo "$FILE" >>$LLIST.3_rebuild
		echo_v "  found $FILE"
		fi
	fi
	done
	echo -e " done.\n  ($LLIST.3_rebuild)"
fi

echo
echo -n -e "${GR}Determining package names$WORKING_TEXT...${NO}"
if [ -f $LLIST.4_names ] ; then
	echo " using existing $LLIST.4_names."
else
    echo_v
    set_trap "$LLIST.4_names"
    for i in `cat $LLIST.3_rebuild`
    do
        /usr/bin/inary -q search-file $i >> $LLIST.tmp
    done
    cat $LLIST.tmp | uniq | sort > $LLIST.4_names
    rm -f $LLIST.tmp
    echo -e " done.\n  ($LIST.4_names)"
fi
cat $LLIST.4_names

path: scripts/revdep-rebuild


code:
#!/bin/sh
#sulinstrapt betiği ile sulinos chroot oluşturabilirsiniz veya diskinize kurulum yapabilirsiniz

if [ "$1" == "" ] || [ "$1" == "-*" ]
then
    echo "Usage: sulinstrapt [directory]"
    exit 0
fi
sulin="$1"
if [ $UID -ne 0 ]
then
    echo "You must be root!"
    exit 1
fi
if [ -d "$sulin" ]
then
  echo "$sulin already exist"
fi
if [ -f "$sulin" ]
then
  echo "$sulin is a file. You must delete or move."
  exit 1
fi
inary ar sulin https://master.dl.sourceforge.net/project/sulinos/SulinRepository/inary-index.xml -D$sulin
inary it -c system.base -y --ignore-scom -D$sulin
cp -prf $sulin/usr/share/baselayout/* $sulin/etc/

path: scripts/sulinstrapt


code:
#!/bin/bash
rsync -avz --delete rsync://rsync.gentoo.org/gentoo-portage/licenses ../licenses/

path: scripts/sync-licenses


code:
#!/bin/bash
if [ $UID -ne 0 ] ; then
    echo "You must be root!"
     exit 1
fi
dest=""
[ "$1" == "" ] || dest="-D$1"
inary dc $dest
inary rdb $dest
inary ur $dest
inary up -c system.base $dest

path: scripts/update-inary-cache


code:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import os
import re
import sys
import hashlib
import datetime
import optparse

def get_and_save_user_info():
    name = "PACKAGER_NAME"
    email = "PACKAGER_EMAIL"

    conf_file = os.path.expanduser("~/.packagerinfo")
    if os.path.exists(conf_file):
        # Read from it
        name, email = open(conf_file, "r").read().strip().split(",")

    else:
        print("Please enter your full name as seen in pspec files")
        name = input("> ")
        print("Please enter your e-mail as seen in pspec files")
        email = input("> ")
        print("Saving packager info into {}".format(conf_file))

        open(conf_file, "w").write("{},{}".format(name, email))

    return name, email

def bump_spec(spec, version, packager_name, packager_email,
          critical, security, bumptype, comment):
    lines = open(spec).readlines()
    name_line = -1
    archive_line = -1
    dep_line = -1
    update_line = -1
    dep_lines = []

    for n, line in enumerate(lines):
        if "<Source>" in line:
            name_line = n + 1

        elif "<Archive" in line:
            archive_line = n

        elif "<Dependency" in line:
            dep_lines.append(n)

        elif "<History>" in line:
            update_line = n + 1

    m = re.match(r" *<Name>(.+)</Name>", lines[name_line])
    name = m.groups()[0]
    lang = name.split("-", 1)[-1]

    m = re.match(r' *<Archive type=".+" sha1sum="(.+)">(.+)</Archive>', lines[archive_line])
    if m is None:
        m = re.match(r' *<Archive sha1sum="(.+)" type=".+">(.+)</Archive>', lines[archive_line])

    sha1sum, uri = m.groups()
    archive_name = os.path.basename(uri)

    m = re.match(r' *<Update release="(.*?)"', lines[update_line])
    release = int(m.groups()[0])

    m = re.match(r" *<Version>(.+)</Version>", lines[update_line + 2])
    old_version = m.groups()[0]

    if not version:
        version = old_version
        new_sha1sum = sha1sum
        new_archive_name = archive_name

    if old_version == version:
        comment = "Package is rebuilded and released up."

    else:
        lines[archive_line] = lines[archive_line].replace(old_version, version)
        new_archive_name = archive_name.replace(old_version, version)

        if not os.path.exists("/var/cache/inary/archives/{}".format(new_archive_name)):
            print("Archive not found downloading via inary...")

            tmp_spec_file = spec_file.replace("pspec", "tmp_pspec")
            open(tmp_spec_file, "w").writelines(lines)
            os.system("sudo inary build {} --fetch".format(tmp_spec_file))
            os.unlink(tmp_spec_file)
        else:
            print("Using existing archive from cache...")

        new_sha1sum = hashlib.sha1(open("/var/cache/inary/archives/{}".format(new_archive_name), 'rb').read()).hexdigest()
        lines[archive_line] = lines[archive_line].replace(sha1sum, new_sha1sum)

    for dep_line in dep_lines:
        m = re.match(r' *<Dependency versionFrom="(.*)">.*', lines[dep_line])
        if m:
            dep_version = m.groups()[0]
            if dep_version == old_version:
                lines[dep_line] = lines[dep_line].replace(old_version, version)

    if not comment=="":
        pass
    else:
        comment="Version bump to {}".format(version)

    if bumptype:
        updatetype = " type=\"{}\"".format(bumptype)
    else:
        updatetype=""

    crit_or_sec = ""

    if security:
        for pkg in security:
            crit_or_sec += "\n            <Type package=\"{}\">security</Type>".format(pkg)
    elif critical:
        for pkg in critical:
            crit_or_sec += "\n            <Type package=\"{}\">critical</Type>".format(pkg)

    update_lines = ['        <Update release="{}">{}\n'.format(release + 1, bumptype or ""),
                    '            <Date>{}</Date>\n'.format(datetime.date.isoformat(datetime.date.today())),
                    '            <Version>{}</Version>\n'.format(version),
                    '            <Comment>{}</Comment>{}\n'.format(comment, crit_or_sec),
                    '            <Name>{}</Name>\n'.format(packager_name),
                    '            <Email>{}</Email>\n'.format(packager_email),
                    '        </Update>\n']

    lines[update_line:update_line] = update_lines

    open(spec_file, "w").writelines(lines)
    print("{} updated".format(spec_file))
    print()
    print("Old SHA1SUM: {}".format(sha1sum))
    print("New SHA1SUM: {}".format(new_sha1sum))
    print("Old Archive: {}".format(archive_name))
    print("New Archive: {}".format(new_archive_name))
    print("Comment: {}".format(comment))
    print("Version: {}".format(version))
    print("Date:    {}".format(datetime.date.isoformat(datetime.date.today())))

if __name__ == "__main__":
    usage = "Usage: %prog <Release comment> [Bumped version] [options] [Pspec list]"
    parser = optparse.OptionParser(usage)
    parser.add_option("--comment",
                      dest="comment",
                      default="",
                      help="Update specfile to x version from old one.")
    parser.add_option("--to-version",
                      dest="to_version",
                      default=None,
                      help="Update specfile to x version from old one.")
    parser.add_option("-n", "--no-increment",
                      dest="no_increment",
                      default=False,
                      help="Do not increment release, just update sha1sums.",
                      action="store_true")
    parser.add_option("-c", "--critical",
                      dest="critical",
                      default=False,
                      help="Mark update as critical and add Type=critical for those packages",
                      action="store_true")
    parser.add_option("-s", "--security",
                      dest="security",
                      default=False,
                      help="Mark update as security and add Type=security for those packages",
                      action="store_true")
    parser.add_option("--all-critical",
                      dest="bumptype",
                      action="store_const",
                      const="critical",
                      help="Mark the update critical for all packages [old way]")
    parser.add_option("--all-security",
                      dest="bumptype",
                      action="store_const",
                      const="security",
                      help="Mark the update security for all packages [old way]")

    (options,args) = parser.parse_args()

    if len(sys.argv) < 2:
        print(usage)
        sys.exit(1)

    files=[]
    for i in sys.argv:
        if i.endswith("pspec.xml"):
            files.append(i)
    if not files:
        print(usage)
        sys.exit(1)

    version = options.to_version
    comment = options.comment
    packager_name, packager_email = get_and_save_user_info()

    for spec_file in files:
        bump_spec(spec_file, version, packager_name, packager_email,
                                      options.critical, options.security,
                                      options.bumptype, comment)

path: scripts/version-bump


code:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# Main fork Pisi: Copyright (C) 2005 - 2011, Tubitak/UEKAE
#
# Copyright (C) 2016 - 2017, Suleyman POYRAZ (Zaryob)
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free
# Software Foundation; either version 2 of the License, or (at your option)
# any later version.
#
# Please read the COPYING file.
#

import os
import shutil
import glob
import sys
import inspect
import tempfile
import subprocess
from distutils.core import setup
from distutils.cmd import Command
from distutils.command.build import build
from distutils.command.install import install
from distutils.sysconfig import get_python_lib

sys.path.insert(0, '.')
import inary

IN_FILES = ("inary.xml.in",)
PROJECT = "inary"
CONFIG_DIR = "/etc/inary"
MIMEFILE_DIR = "/usr/share/mime/packages"
TMPFILES_DIR = "/usr/lib/tmpfiles.d"

class Build(build):
    def run(self):
        # Preparing configure file
        shutil.copy("config/inary.conf-{}".format(os.uname().machine), "config/inary.conf")

        build.run(self)

        self.mkpath(self.build_base)

        for in_file in IN_FILES:
            name, ext = os.path.splitext(in_file)
            self.spawn(["intltool-merge", "-x", "po", in_file, os.path.join(self.build_base, name)])

class BuildPo(build):
    def run(self):
        build.run(self)
        self.build_po()

    @staticmethod
    def build_po():
        import optparse
        files = tempfile.mkstemp()[1]
        filelist = []

        # Include optparse module path to translate
        optparse_path = os.path.abspath(optparse.__file__).rstrip("co")

        # Collect headers for mimetype files
        for filename in IN_FILES:
            os.system("intltool-extract --type=gettext/xml {}".format(filename))

        for root, dirs, filenames in os.walk("inary"):
            for filename in filenames:
                if filename.endswith(".py"):
                    filelist.append(os.path.join(root, filename))

        filelist.extend(["inary-cli", "inary.xml.in.h", optparse_path])
        filelist.sort()
        with open(files, "w") as _files:
            _files.write("\n".join(filelist))

        # Generate POT file
        os.system("xgettext -L Python \
                            --default-domain={0} \
                            --keyword=_ \
                            --keyword=N_ \
                            --files-from={1} \
                            -o po/{2}.pot".format(PROJECT, files, PROJECT))

        # Update PO files
        for item in glob.glob1("po", "*.po"):
            print("Updating .. ", item)
            os.system("msgmerge --update --no-wrap --sort-by-file po/{0} po/{1}.pot".format(item, PROJECT))

        # Cleanup
        os.unlink(files)
        for f in filelist:
            if not f.endswith(".h"):
                continue
            try:
                os.unlink(f)
            except OSError:
                pass

class Install(install):
    def run(self):
        install.run(self)
        self.installi18n()
        self.generateConfigFile()

    def finalize_options(self):
        # NOTE: for Sulin distribution
        if os.path.exists("/etc/sulin-release"):
            self.install_platlib = '$base/lib/sulin'
            self.install_purelib = '$base/lib/sulin'
        install.finalize_options(self)

    def installi18n(self):
        for name in os.listdir('po'):
            if not name.endswith('.po'):
                continue
            lang = name[:-3]
            print("Installing '{}' translations...".format(lang))
            os.system("msgfmt po/{0}.po -o po/{0}.mo".format(lang))
            if not self.root:
                self.root = "/"
            destpath = os.path.join(self.root, "usr/share/locale/{}/LC_MESSAGES".format(lang))
            if not os.path.exists(destpath):
                os.makedirs(destpath)
            shutil.copy("po/{}.mo".format(lang), os.path.join(destpath, "inary.mo"))

    def generateConfigFile(self):
        import inary.configfile
        destpath = os.path.join(self.root, CONFIG_DIR)
        if not os.path.exists(destpath):
            os.makedirs(destpath)

        confFile = os.path.join(destpath, "inary.conf")
        if os.path.isfile(confFile):  # Don't overwrite existing inary.conf
            return

        inaryconf = open(confFile, "w")

        klasses = inspect.getmembers(inary.configfile, inspect.isclass)
        defaults = [klass for klass in klasses if klass[0].endswith('Defaults')]

        for d in defaults:
            section_name = d[0][:-len('Defaults')].lower()
            inaryconf.write("[{}]\n".format(section_name))

            section_members = [m for m in inspect.getmembers(d[1]) \
                               if not m[0].startswith('__') \
                               and not m[0].endswith('__')]

            for member in section_members:
                if member[1] is None or member[1] == "":
                    inaryconf.write("# {0[0]} = {0[1]}\n".format(member))
                else:
                    inaryconf.write("{0[0]} = {0[1]}\n".format(member))
            inaryconf.write('\n')

class Test(Command):
    user_options = []

    def initialize_options(self):
        pass

    def finalize_options(self):
        pass

    def run(self):
        self.run_command('build')
        os.chdir('tests')
        subprocess.check_call([
            sys.executable, '-bWd',
            os.path.join('runTests.py')
        ])

setup(name="inary",
      version=inary.__version__,
      description="Inary (Special Package Manager)",
      long_description="Inary is the package management system of Sulin Linux.",
      license="GNU GPLv3",
      author="Zaryob",
      author_email="zaryob.dev@gmail.com",
      url="https://github.com/Zaryob/inary",
      # package_dir = {'': ''},

      packages=['inary',
                'inary.actionsapi',
                'inary.analyzer',
                'inary.cli',
                'inary.data',
                'inary.db',
                'inary.libraries',
                'inary.operations',
                'inary.sxml'],
      cmdclass={'build': Build,
                'build_po': BuildPo,
                'install': Install,
                'test': Test},
      data_files=[(CONFIG_DIR, ["config/inary.conf", "config/mirrors.conf", "config/sandbox.conf"]),
                  (MIMEFILE_DIR, ["build/inary.xml"])],
      scripts=['inary-cli',
               'scripts/pspec2po',
               'scripts/revdep-rebuild',
               'scripts/sulinstrapt',
               'scripts/update-inary-cache',
               'scripts/version-bump'],
      classifiers=[
          'Development Status :: 5 - Production/Stable',
          'Environment :: Console',
          'Environment :: Plugins',
          'Framework :: Sphinx',
          'Intended Audience :: End Users/Desktop',
          'Intended Audience :: Developers',
          'Intended Audience :: System Administrators',
          'License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)',
          'License :: OSI Approved :: GNU General Public License v2 or later (GPLv2+)',
          'Natural Language :: English',
          'Natural Language :: Dutch',
          'Natural Language :: French',
          'Natural Language :: German',
          'Natural Language :: Hungarian',
          'Natural Language :: Italian',
          'Natural Language :: Portuguese (Brazilian)',
          'Natural Language :: Russian',
          'Natural Language :: Slovak',
          'Natural Language :: Turkish',
          'Natural Language :: Ukrainian',
          'Operating System :: MacOS :: MacOS X',
          'Operating System :: POSIX',
          'Operating System :: POSIX :: BSD',
          'Programming Language :: Python :: 3 :: Only',
          'Topic :: Desktop Environment',
          'Topic :: System',
          'Topic :: System :: Installation/Setup',
          'Topic :: Software Development :: Bug Tracking',
          ],
      )

# the below stuff is really nice but we already have a version
# we can use this stuff for svn snapshots in a separate
# script, or with a parameter I don't know -- exa

INARY_VERSION = inary.__version__


code:
Inary UnitTests
##############

Before running unittests you need to first go to repos directory and
create test repositories.

>>> test@sulin tests/repos# python3 createrepos.py

Now you can return to tests folder and run tests.

>>> test@sulin tests # python3 runtests.py

path: tests/README


code:
# -*- coding: utf-8 -*-
#
# Copyright (C) 2018, Suleyman POYRAZ (Zaryob)
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free
# Software Foundation; either version 2 of the License, or (at your option)
# any later version.
#
# Please read the COPYING file.
#


code:
# -*- coding: utf-8 -*-
#
# Copyright (C) 2018, Suleyman POYRAZ (Zaryob)
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free
# Software Foundation; either version 2 of the License, or (at your option)
# any later version.
#
# Please read the COPYING file.
#

import inary
import inary.db
import unittest
from . import testcase

class ComponentDBTestCase(testcase.TestCase):

    def setUp(self):
        testcase.TestCase.setUp(self)
        self.componentdb = inary.db.componentdb.ComponentDB()

    def testHasComponent(self):
        self.assertTrue(self.componentdb.has_component("system.base", "core-binary"))
        self.assertFalse(self.componentdb.has_component("floct.flict", "core-binary"))
        self.assertTrue(self.componentdb.has_component("multimedia.graphics", "core-src"))
        self.assertFalse(self.componentdb.has_component("floct.flict", "core-src"))
        self.assertTrue(self.componentdb.has_component("programming.language.python"))

    def testListComponents(self):
        self.assertEqual(set(self.componentdb.list_components(repo="core-binary")),set(['util.shell', 'programming.environment.kdevelop',
                                                                                'programming.environment.eclipse', 'system.devel',
                                                                                'util.archive', 'programming.tool', 'office.docbook',
                                                                                'multimedia', 'desktop', 'util.admin', 'x11',
                                                                                'x11.library', 'programming.devel', 'util',
                                                                                'util.crypt', 'hardware.disk', 'system.boot',
                                                                                'hardware', 'system.pages', 'system.locale',
                                                                                'tex.base', 'x11.util', 'office', 'system',
                                                                                'desktop.font', 'system.base', 'programming.library',
                                                                                'programming.environment.eric', 'tex',
                                                                                'programming', 'programming.language.python',
                                                                                'programming.environment', 'util.misc',
                                                                                'multimedia.graphics', 'system.doc',
                                                                                'programming.language', 'programming.docs']))

        if set(["applications", "applications.util", "applications.network"]) not in set(self.componentdb.list_components()):
            assert True
        else:
            assert False

    def testGetComponent(self):
        component = self.componentdb.get_component("system.base")
        self.assertEqual(component.name, "system.base")
        self.assertIn("expat", component.packages)
        self.assertNotIn("expat-devel", component.packages)

        component = self.componentdb.get_component("util.admin", repo="core-binary")
        self.assertEqual(component.name,"util.admin")
        self.assertIn("libcap-ng-utils", component.packages)
        self.assertNotIn("ncftp", component.packages)

    def testGetUnionComponent(self):
        component = self.componentdb.get_union_component("system.locale")
        self.assertEqual(component.name, "system.locale")
        self.assertIn("glibc-locales-so", component.packages)
        self.assertNotIn("minizip", component.packages)

    def testGetPackages(self):
        packages = self.componentdb.get_packages("system.devel")
        self.assertIn("expat-devel", packages)
        self.assertNotIn("expat", packages)

        packages = self.componentdb.get_packages("util.misc", repo="core-binary")
        self.assertIn("uuidd", packages)
        self.assertNotIn( "ncftp", packages)

        packages = self.componentdb.get_packages("system.pages", walk = True)
        self.assertIn("autoconf-pages" and "autoconf-pages",packages)

    def testGetSources(self):
        packages = self.componentdb.get_sources("system.devel")
        self.assertIn("isl", packages)
        self.assertNotIn( "ncftp", packages)

        packages = self.componentdb.get_sources("system.devel", repo="core-binary")
        self.assertEqual([], packages)

        packages = self.componentdb.get_packages("system.devel", walk = True)
        self.assertIn("ppl" and "expat-devel", packages)

    def testGetUnionPackages(self):
        packages = self.componentdb.get_union_packages("programming.devel")
        self.assertIn('device-mapper-event-devel',packages)
        self.assertNotIn( "ncftp", packages)

        packages = self.componentdb.get_union_packages("system.pages", walk = True)
        assert "autoconf-pages" and "autoconf-pages" in packages

    def testSearchComponent(self):
        packages = self.componentdb.search_component(["yst"])
        self.assertIn('system.base', set(packages))
        self.assertNotIn('programming', set(packages))

        packages = self.componentdb.search_component(["doc"], repo="core-binary")
        self.assertIn("system.doc", packages)

        packages = self.componentdb.search_component(["til", "isc"],  repo="core-binary")
        self.assertIn("util.misc", packages)


code:
# -*- coding: utf-8 -*-
#
# Copyright (C) 2018, Suleyman POYRAZ (Zaryob)
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free
# Software Foundation; either version 2 of the License, or (at your option)
# any later version.
#
# Please read the COPYING file.
#

import inary
import inary.context as ctx
import unittest
from . import testcase

class FilesDBTestCase(testcase.TestCase):

    filesdb = inary.db.filesdb.FilesDB()

    def testHasFile(self):
        self.assertFalse(self.filesdb.has_file("etc/protocols"))
        inary.api.install(["iana-etc"])
        self.assertTrue(self.filesdb.has_file("etc/protocols"))
        self.assertTrue(self.filesdb.has_file("etc/services"))
        inary.api.remove(["iana-etc"])
        self.assertFalse(self.filesdb.has_file("etc/protocols"))

    def testGetFile(self):
        inary.api.install(["iana-etc"])
        pkg, path = self.filesdb.get_file("etc/protocols")
        self.assertEqual(pkg, "iana-etc")
        self.assertEqual(path, "etc/protocols")
        inary.api.remove(["iana-etc"])
        self.assertFalse(self.filesdb.has_file("etc/protocols"))

    def testAddRemoveFiles(self):
        fileinfo1 = inary.data.files.FileInfo()
        fileinfo1.path = "etc/inary/inary.conf"
        fileinfo2 = inary.data.files.FileInfo()
        fileinfo2.path = "etc/inary/mirrors.conf"

        files = inary.data.files.Files()
        files.list.append(fileinfo1)
        files.list.append(fileinfo2)

        self.assertFalse(self.filesdb.has_file("etc/inary/inary.conf"))
        self.assertFalse(self.filesdb.has_file("etc/inary/mirrors.conf"))

        self.filesdb.add_files("inary", files)

        self.assertTrue(self.filesdb.has_file("etc/inary/inary.conf"))
        self.assertTrue(self.filesdb.has_file("etc/inary/mirrors.conf"))

        pkg, path = self.filesdb.get_file("etc/inary/inary.conf")
        self.assertEqual(pkg, "inary")

        # FIXME: inconsistency in filesdb.py add_remove and remove_remove parameters
        self.filesdb.remove_files(files.list)

        self.assertFalse(self.filesdb.has_file("etc/inary/inary.conf"))
        self.assertFalse(self.filesdb.has_file("etc/inary/mirrors.conf"))

    def testSearchFile(self):
        self.assertFalse(self.filesdb.search_file("protocols"))
        inary.api.install(["iana-etc"])
        self.assertTrue(self.filesdb.search_file("protocols"))
        inary.api.remove(["iana-etc"])


code:
# -*- coding: utf-8 -*-
#
# Copyright (C) 2018, Suleyman POYRAZ (Zaryob)
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free
# Software Foundation; either version 2 of the License, or (at your option)
# any later version.
#
# Please read the COPYING file.
#

import inary
import inary.data
import inary.db
import unittest
from . import testcase

class InstallDBTestCase(testcase.TestCase):

    def setUp(self):
        testcase.TestCase.setUp(self)

        self.installdb = inary.db.installdb.InstallDB()

    def tearDown(self):
        inary.api.remove(["timezone", "time", "acl", "attr"])

    def testGetPackage(self):
        inary.api.install(["timezone"])
        idb = inary.db.installdb.InstallDB()
        pkg = idb.get_package("timezone")
        self.assertEqual(type(pkg), inary.data.metadata.Package)
        self.assertEqual(pkg.name, "timezone")

    def testHasPackage(self):
        inary.api.install(["timezone"])
        self.installdb = inary.db.installdb.InstallDB()
        self.assertFalse(self.installdb.has_package("flipfloo"))
        self.assertTrue(self.installdb.has_package("timezone"))

    def testListInstalled(self):
        inary.api.install(["timezone", "time"])
        self.installdb = inary.db.installdb.InstallDB()
        self.assertEqual(set(self.installdb.list_installed()), set(["timezone", "time"]))

    def testGetVersion(self):
        inary.api.install(["timezone"])
        self.installdb = inary.db.installdb.InstallDB()
        version, release, build = self.installdb.get_version("timezone")
        self.assertEqual(version, "2018e")
        self.assertEqual(release, "1")
        self.assertEqual(build, None)

    def testGetFiles(self):
        inary.api.install(["timezone"])
        self.installdb = inary.db.installdb.InstallDB()
        files = self.installdb.get_files("timezone")
        self.assertIn("usr/share/zoneinfo/Portugal", [x.path for x in files.list])
        self.assertNotIn("usr/bin", [x.path for x in files.list])

    def testGetInfo(self):
        inary.api.install(["timezone"])
        idb = inary.db.installdb.InstallDB()
        info = idb.get_info("timezone")
        self.assertTrue(isinstance(info, inary.db.installdb.InstallInfo))
        self.assertEqual(info.version, "2018e")

    def testGetReverseDependencies(self):
        inary.api.install(["acl"])
        self.installdb = inary.db.installdb.InstallDB()
        revdeps = self.installdb.get_rev_deps("acl")
        self.assertIn(set(["attr"]), set(map(lambda x:x[0], revdeps)))

    def testAddRemovePackage(self):
        inary.api.install(["time"])
        self.installdb = inary.db.installdb.InstallDB()
        self.assertTrue(self.installdb.has_package("time"))
        self.assertFalse(self.installdb.has_package("timezone"))
        inary.api.install(["timezone"])
        self.installdb = inary.db.installdb.InstallDB()
        self.assertTrue(self.installdb.has_package("time"))
        self.assertTrue(self.installdb.has_package("timezone"))

    def testMarkListPending(self):
        self.skipTest(reason="")

    def testClearPending(self):
        self.skipTest(reason="")

    def testSearchPackage(self):
        self.installdb = inary.db.installdb.InstallDB()
        self.assertFalse(self.installdb.has_package("timezone"))
        self.assertFalse(self.installdb.search_package(["timezone"]))
        inary.api.install(["timezone"])
        self.installdb = inary.db.installdb.InstallDB()
        self.assertEqual(self.installdb.search_package(["t", "ime", "zone"]), ["timezone"])


code:
# -*- coding: utf-8 -*-
#
# Copyright (C) 2018, Suleyman POYRAZ (Zaryob)
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free
# Software Foundation; either version 2 of the License, or (at your option)
# any later version.
#
# Please read the COPYING file.
#

import unittest
from . import testcase

import inary.db.itembyrepo

class TestDB:
    def __init__(self):
        self.packages = {}
        self.obsoletes = {}

        self.packages["repo1"] = {"aggdraw":"package aggdraw",
                                        "acpica":"package acpica"}
        self.packages["repo2"] = {"kdiff3":"package kdiff3",
                                         "kmess":"package kmess"}

        self.obsoletes["repo1"] = ["wengophone", "rar"]
        self.obsoletes["repo2"] = ["xara"]

        self.tdb = inary.db.itembyrepo.ItemByRepo(self.packages)
        self.odb = inary.db.itembyrepo.ItemByRepo(self.obsoletes)

        # original item_repos in ItemByRepo uses repodb.list_repos
        def item_repos(repo=None):
            repos = ["repo1", "repo2"]
            if repo:
                repos = [repo]
            return repos

        self.tdb.item_repos = item_repos
        self.odb.item_repos = item_repos

class ItemByRepoTestCase(testcase.TestCase):

    testdb = TestDB()

    def testHasRepository(self):
        self.assertTrue(self.testdb.tdb.has_repo("repo1"))
        self.assertTrue(self.testdb.tdb.has_repo("repo2"))
        self.assertFalse(self.testdb.tdb.has_repo("hedehodo"))

    def testHasItem(self):
        self.assertTrue(self.testdb.tdb.has_item("kdiff3", "repo2"))
        self.assertFalse(self.testdb.tdb.has_item("kdiff3", "repo1"))
        self.assertTrue(self.testdb.tdb.has_item("acpica"))

    def testWhichRepo(self):
        self.assertEqual(self.testdb.tdb.which_repo("aggdraw"), "repo1")
        self.assertEqual(self.testdb.tdb.which_repo("kmess"), "repo2")

    def testGetItemAndRepository(self):
        pkg, repo = self.testdb.tdb.get_item_repo("acpica")
        self.assertEqual(pkg, "package acpica")
        self.assertEqual(repo, "repo1")

        pkg, repo = self.testdb.tdb.get_item_repo("kmess")
        self.assertEqual(pkg, "package kmess")
        self.assertEqual(repo, "repo2")

    def testItemRepos(self):
        db = inary.db.itembyrepo.ItemByRepo({})
        self.assertEqual(db.item_repos("caracal"), ["caracal"])
        # repos were created by testcase.py
        self.assertEqual(db.item_repos(), ['core-src', 'core-binary'])

    def testGetItem(self):
        self.assertEqual(self.testdb.tdb.get_item("acpica"), "package acpica")
        self.assertEqual(self.testdb.tdb.get_item("kmess"), "package kmess")

    def testGetItemOfRepository(self):
        self.assertEqual(self.testdb.tdb.get_item("acpica", "repo1"), "package acpica")
        self.assertEqual(self.testdb.tdb.get_item("kmess", "repo2"), "package kmess")

    def testGetItemKeys(self):
        self.assertEqual(set(self.testdb.tdb.get_item_keys("repo1")), set(["aggdraw", "acpica"]))
        self.assertEqual(set(self.testdb.tdb.get_item_keys("repo2")), set(["kdiff3", "kmess"]))
        self.assertEqual(set(self.testdb.tdb.get_item_keys()), set(["kdiff3", "kmess", "aggdraw", "acpica"]))

    def testGetListItem(self):
        self.assertEqual(set(self.testdb.odb.get_list_item("repo1")), set(['rar', 'wengophone']))
        self.assertEqual(set(self.testdb.odb.get_list_item("repo2")), set(['xara']))
        self.assertEqual(set(self.testdb.odb.get_list_item()), set(['rar', 'xara', 'wengophone']))


code:
# -*- coding: utf-8 -*-
#
# Copyright (C) 2018, Suleyman POYRAZ (Zaryob)
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free
# Software Foundation; either version 2 of the License, or (at your option)
# any later version.
#
# Please read the COPYING file.
#

import unittest
from . import testcase
import inary.db.lazydb as lazydb

class TestDB(lazydb.LazyDB):

    def init(self):
        self.testfield = True

    def getTestField(self):
        return self.testfield

class LazyDBTestCase(testcase.TestCase):

    def testDatabaseMethodForcingInit(self):
        db = TestDB()
        assert db.getTestField()
        assert "testfield" in db.__dict__
        db._delete()

    def testDatabaseWithoutInit(self):
        db = TestDB()
        assert not "testfield" in db.__dict__
        db._delete()

    def testSingletonBehaviour(self):
        db = TestDB()
        db2 = TestDB()
        assert id(db) == id(db2)


code:
# -*- coding: utf-8 -*-
#
# Copyright (C) 2018, Suleyman POYRAZ (Zaryob)
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free
# Software Foundation; either version 2 of the License, or (at your option)
# any later version.
#
# Please read the COPYING file.
#

import unittest
from . import testcase
import inary

class PackageDBTestCase(testcase.TestCase):

    def setUp(self):
        testcase.TestCase.setUp(self)

        self.packagedb = inary.db.packagedb.PackageDB()

    def testGetPackage(self):
        pkg = self.packagedb.get_package("bash", "core-binary")
        self.assertEqual(pkg.name, "bash")

        pkg = self.packagedb.get_package("grep", "core-src")
        self.assertEqual(pkg.name, "grep")

        pkg = self.packagedb.get_package("expat")
        self.assertEqual(pkg.name, "expat")

    def testHasPackage(self):
        self.assertTrue(self.packagedb.has_package("tar", "core-binary"))
        self.assertFalse(self.packagedb.has_package("tar", "core-src"))
        self.assertTrue(self.packagedb.has_package("zlib"))

    def testGetVersion(self):
        version, release, build = self.packagedb.get_version("bash", "core-binary")
        self.assertEqual(version, "5.0")
        self.assertEqual(release, "1")

    def testWhichRepo(self):
        self.assertEqual(self.packagedb.which_repo("bash"), "core-binary")

    def testGetPackageAndRepository(self):
        pkg, repo = self.packagedb.get_package_repo("gcc")
        self.assertEqual(pkg.name, "gcc")
        self.assertEqual(repo, "core-binary")

    def testGetObsoletes(self):
        self.assertEqual(self.packagedb.get_obsoletes(), [])

    def testGetReverseDependencies(self):
        pkg, dep = self.packagedb.get_rev_deps("bash")[0]
        assert pkg == "bash-dbginfo"
        assert str(dep) == "bash release 1"

    def testGetReplaces(self):
        # FIXME: update createrepo.py to generate replaces
        assert not self.packagedb.get_replaces()

    def testListPackages(self):
        self.assertIn("expat", self.packagedb.list_packages("core-binary"))

    def testSearchPackage(self):
        packages = self.packagedb.search_package(["osd","doc"])
        self.assertIn('biosdevname-docs', packages)

        packages = self.packagedb.search_package(["32bit","bus"],repo="core-binary")
        self.assertIn('dbus-32bit', packages)


code:
# -*- coding: utf-8 -*-
#
# Copyright (C) 2018, Suleyman POYRAZ (Zaryob)
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free
# Software Foundation; either version 2 of the License, or (at your option)
# any later version.
#
# Please read the COPYING file.
#

import inary
import unittest
from . import testcase

class RepoDBTestCase(testcase.TestCase):

    def setUp(self):
        testcase.TestCase.setUp(self)

        self.repodb = inary.db.repodb.RepoDB()

    def testAddRemoveRepo(self):
        self.assertNotIn("repo2-src", self.repodb.list_repos())
        repo = inary.db.repodb.Repo(inary.uri.URI("repos/repo2/inary-index.xml"))
        self.repodb.add_repo("repo2-src", repo)
        self.assertIn("repo2-src",self.repodb.list_repos())
        self.repodb.remove_repo("repo2-src")
        self.assertIn("core-src", self.repodb.list_repos())
        self.assertIn("core-binary", self.repodb.list_repos())
        self.assertNotIn("repo2-src", self.repodb.list_repos())

    def testAddRemoveCycle(self):
        for r in range(30):
            self.assertNotIn("test-repo",self.repodb.list_repos())
            repo = inary.db.repodb.Repo(inary.uri.URI("http://test-repo/inary-index.xml"))
            self.repodb.add_repo("test-repo", repo)
            self.assertIn("test-repo", self.repodb.list_repos())
            self.repodb.remove_repo("test-repo")

        self.assertNotIn("test-repo", self.repodb.list_repos())

    def testListRepos(self):
        self.assertEqual(set(self.repodb.list_repos()), set(['core-src', 'core-binary']))

    def testGetSourceRepos(self):
        self.assertEqual(set(self.repodb.get_source_repos()), set(['core-src']))

    def testGetBinaryRepos(self):
        self.assertEqual(set(self.repodb.get_binary_repos()), set(['core-binary']))

    def testGetRepo(self):
        repo = self.repodb.get_repo("core-src")
        uri = repo.indexuri
        self.assertEqual(uri.get_uri(), "http://127.0.0.1/SulinRepository/inary-index.xml")

    def testRepoOrder(self):
        repoorder = inary.db.repodb.RepoOrder()
        self.assertEqual(repoorder.get_order(), ['core-src', 'core-binary'])

        repoorder.add("test-repo", "http://test-repo/inary-index.xml")
        self.assertEqual(repoorder.get_order(), ['core-src', 'core-binary', 'test-repo'])

        repoorder.remove("test-repo")
        self.assertEqual(repoorder.get_order(), ['core-src', 'core-binary'])


code:
# -*- coding: utf-8 -*-
#
# Copyright (C) 2018, Suleyman POYRAZ (Zaryob)
#
# This program is free software; you can redistribute it and/or modify it under the terms of the GNU General
# Public License as published by the Free Software Foundation; either version 3 of the License, or (at your
# option) any later version.
#
# Please read the COPYING file.
#

import unittest
from . import testcase
import os
import inary.operations.search
import inary.db as db

class SearchTestCase(testcase.TestCase):
    def setUp(self):
        testcase.TestCase.setUp(self)

    def testSearch(self):
        doc1 = "A set object is an unordered collection of immutable values."
        doc2 = "Being an unordered collection, sets do not record element position or order of insertion."
        doc3 = "There are currently two builtin set types, set and frozenset"
        inary.search.init(['test'], ['en'])
        inary.search.add_doc('test', 'en', 1, doc1, repo = db.itembyrepo.installed)
        inary.search.add_doc('test', 'en', 2, doc2, repo = db.itembyrepo.installed)
        inary.search.add_doc('test', 'en', 3, doc3, repo = db.itembyrepo.installed)
        q1 = inary.search.query('test', 'en', ['set'], repo = db.itembyrepo.alldb)
        self.assertEqual(q1, set([1,3]))
        q2 = inary.search.query('test', 'en', ['an', 'collection'], repo = db.itembyrepo.alldb)
        self.assertEqual(q2, set([1,2]))
        inary.search.finalize()


code:
# -*- coding: utf-8 -*-
#
# Copyright (C) 2018, Suleyman POYRAZ (Zaryob)
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free
# Software Foundation; either version 2 of the License, or (at your option)
# any later version.
#
# Please read the COPYING file.
#

import unittest
from . import testcase
import inary

class SourceDBTestCase(testcase.TestCase):

    def setUp(self):
        testcase.TestCase.setUp(self)
        self.sourcedb = inary.db.sourcedb.SourceDB()

    def testListSources(self):
        self.skipTest(reason="")

    def testHasSpec(self):
        assert self.sourcedb.has_spec("openssl")
        assert not self.sourcedb.has_spec("hedehodo")

    def testGetSpec(self):
        spec = self.sourcedb.get_spec("zlib")
        assert spec.source.name == "zlib"
        assert spec.source.partOf == "system.base"

    def testGetSpecOfRepository(self):
        spec = self.sourcedb.get_spec("xz", "core-src")
        assert spec.source.name == "xz"
        assert spec.source.partOf == "system.base"

    def testGetSpecAndRepository(self):
        spec, repo = self.sourcedb.get_spec_repo("openssl")
        assert spec.source.name == "openssl"
        assert spec.source.partOf == "system.base"
        assert repo == "core-src"

    def testGetSourceFromPackage(self):
        pkg = self.sourcedb.pkgtosrc("xz")
        assert pkg == "xz"

    def testSearchPackage(self):
        packages = self.sourcedb.search_spec(["open", "ssl"])
        assert set(["openssl"]) == set(packages)

        packages = self.sourcedb.search_spec(["xorg", "util"], repo="core-src")
        assert set(["xorg-util"]) == set(packages)


code:
import unittest
import inary
import inary.context as ctx

import inary.db.repodb
import inary.operations.repository as repository

class TestCase(unittest.TestCase):

    def setUp(self):
        options = inary.config.Options()
        options.destdir = 'tests/tmp_root'
        inary.api.set_options(options)
        inary.api.set_scom(False)
        ctx.config.values.general.distribution = "Sulin"
        ctx.config.values.general.distribution_release = "2019"
        ctx.config.values.general.ignore_safety=True

        if not inary.db.repodb.RepoDB().list_repos():
            #repository.add_repo("core-src", "https://gitlab.com/Zaryob/SulinRepository/raw/master/inary-index.xml")
            #repository.add_repo("core-binary", "https://sourceforge.net/projects/sulinos/files/packages/indispensable/inary-index.xml")
            repository.add_repo("core-src", "http://127.0.0.1/SulinRepository/inary-index.xml")
            repository.add_repo("core-binary", "http://127.0.0.1/indispensable/inary-index.xml.xz")
        repository.update_repo("core-src")
        repository.update_repo("core-binary")