<commit_before>import time

from mint import buildtypes
from mint import helperfuncs
from mint import jobstatus
from mint.lib import data
from mint.lib import database
from mint.mint_error import *

class UrlDownloadsTable(database.DatabaseTable):
    name = "UrlDownloads"
    fields = ['urlId', 'timeDownloaded', 'ip']

    def add(self, urlId, ip):
        t = helperfuncs.toDatabaseTimestamp()
        cu = self.db.cursor()
        cu.execute("""INSERT INTO UrlDownloads (urlId, timeDownloaded, ip)
            VALUES (?, ?, ?)""",
            urlId, t, ip)
        self.db.commit()


class BuildsTable(database.KeyedTable):
    name = "Builds"
    key  = "buildId"

    fields = ['buildId', 'projectId', 'pubReleaseId',
              'buildType', 'name', 'description',
              'troveName', 'troveVersion', 'troveFlavor', 'troveLastChanged',
              'timeCreated', 'createdBy', 'timeUpdated', 'updatedBy',
              'buildCount', 'productVersionId', 'stageName',
              'status', 'statusMessage']

    def iterBuildsForProject(self, projectId):
        """ Returns an iterator over the all of the buildIds in a given
            project with ID projectId. The iterator is ordered by the date
            the associated group grove last changed in descending order
            (most to lease recent)."""

        cu = self.db.cursor()

        cu.execute("""SELECT buildId FROM Builds
                      WHERE projectId=? AND
                            troveName IS NOT NULL AND
                            troveVersion IS NOT NULL AND
                            troveFlavor IS NOT NULL AND
                            troveLastChanged IS NOT NULL
                            ORDER BY troveLastChanged DESC, buildId""",
                   projectId)

        for results in cu.fetchall():
            yield results[0]

    def setTrove(self, buildId, troveName, troveVersion, troveFlavor):
        cu = self.db.cursor()
        cu.execute("""UPDATE Builds SET troveName=?,
                                          troveVersion=?,
                                          troveFlavor=?,
                                          troveLastChanged=?
                      WHERE buildId=?""",
                   troveName, troveVersion,
                   troveFlavor, time.time(),
                   buildId)
        self.db.commit()
        return 0

    def setProductVersion(self, buildId, versionId, stageName):
        cu = self.db.cursor()
        cu.execute("""UPDATE Builds SET productVersionId=?,
                                          stageName=?,
                                          troveLastChanged=?
                      WHERE buildId=?""",
                   versionId, stageName,
                   time.time(), buildId)
        self.db.commit()

    def getTrove(self, buildId):
        cu = self.db.cursor()

        cu.execute("""SELECT troveName,
                             troveVersion,
                             troveFlavor
                      FROM Builds
                      WHERE buildId=?""",
                   buildId)
        r = cu.fetchone()

        name, version, flavor = r[0], r[1], r[2]
        if not flavor:
            flavor = "none"
        if not name or not version:
            raise TroveNotSet
        else:
            return name, version, flavor

    def getPublished(self, buildId):
        cu = self.db.cursor()
        cu.execute("SELECT COALESCE((SELECT pubReleaseId FROM Builds WHERE buildId=?), 0)", buildId)
        pubReleaseId = cu.fetchone()[0]
        if pubReleaseId:
            cu.execute("SELECT timePublished FROM PublishedReleases WHERE pubReleaseId = ?", pubReleaseId)
            res = cu.fetchone()
            if res:
                return bool(res[0])
        return False

    def getUnpublishedBuilds(self, projectId):
        cu = self.db.cursor()
        cu.execute("""SELECT buildId FROM Builds
                      WHERE projectId = ? AND pubReleaseId IS NULL""",
                      projectId)
        res = cu.fetchall()
        return [x[0] for x in res]

    def buildExists(self, buildId):
        cu = self.db.cursor()

        cu.execute("SELECT count(*) FROM Builds WHERE buildId=?", buildId)
        return cu.fetchone()[0]

    def bumpBuildCount(self, buildId):
        # This is a post-increment, unlike bumpCookCount, since we always want
        # to look at the last build.
        cu = self.db.cursor()
        cu.execute("SELECT buildCount FROM Builds WHERE buildId=?",
                   buildId)
        res = cu.fetchall()
        if res:
            count = res[0][0] + 1
            cu.execute("""UPDATE Builds
                              SET buildCount=?,
                              status=?,
                              statusMessage=?
                              WHERE buildId=?""", count, jobstatus.WAITING,
                              jobstatus.statusNames[jobstatus.WAITING],
                              buildId)
            return count
        else:
            return None

    @staticmethod
    def _filterBuildVisibility(rs, okHiddenProjectIds, limitToUserId):
        # admins see all
        if not limitToUserId:
            return True
        else:
            # restrict hidden projects unless you're a member
            if (not rs['isPrivate'] or (rs['isPrivate'] and (rs['projectId'] in okHiddenProjectIds))) and \
               (rs['isPublished'] or ((not rs['isPublished']) and (rs['role'] in ('Product Developer', 'Product Owner')))):
                return True
        return False

    def getAllBuildsByType(self, imageType, requestingUserId, 
                           limitToUserId=False):
        extraWhere = ''
        # by default, we organize builds by sha1.  This assumes
        # that builds have one file and that one file is the build.
        # not sure how to deal w/ error logs being associated since
        # we don't have an error status.
        extraSelect = ', bdf.sha1'
        extraJoin = ' JOIN buildFiles bdf ON (bdf.buildId = b.buildId)'
        if imageType == 'AMI':
            # cancel out sha1 join - we don't have any files with this build!
            extraJoin = ''

            # Extra selects:
            # add in awsAccount if it exists.
            extraSelect = ''', COALESCE(ud.value,'Unknown') AS awsAccountNumber,
                             bd.value AS amiId'''
            extraJoin += '''LEFT OUTER JOIN userData ud
                            ON (b.createdBy = ud.userId
                                AND ud.name = 'awsAccountNumber')'''

            # make sure that this build has an amiId.  Since it doesn't
            # have any files (thus no sha1), we need to know that it
            # has an amiId to know it uploaded correctly
            extraJoin += ''' JOIN buildData bd
                             ON (bd.buildId  = b.buildId
                                 AND bd.name = 'amiId')'''
        elif imageType == 'VWS':
            # VWS as a build type doesn't currently exist, but any<commit_msg>Fix duplicate images returned to catalog-service when the image has multiple files.<commit_after>import time

from mint import buildtypes
from mint import helperfuncs
from mint import jobstatus
from mint.lib import data
from mint.lib import database
from mint.mint_error import *

class UrlDownloadsTable(database.DatabaseTable):
    name = "UrlDownloads"
    fields = ['urlId', 'timeDownloaded', 'ip']

    def add(self, urlId, ip):
        t = helperfuncs.toDatabaseTimestamp()
        cu = self.db.cursor()
        cu.execute("""INSERT INTO UrlDownloads (urlId, timeDownloaded, ip)
            VALUES (?, ?, ?)""",
            urlId, t, ip)
        self.db.commit()


class BuildsTable(database.KeyedTable):
    name = "Builds"
    key  = "buildId"

    fields = ['buildId', 'projectId', 'pubReleaseId',
              'buildType', 'name', 'description',
              'troveName', 'troveVersion', 'troveFlavor', 'troveLastChanged',
              'timeCreated', 'createdBy', 'timeUpdated', 'updatedBy',
              'buildCount', 'productVersionId', 'stageName',
              'status', 'statusMessage']

    def iterBuildsForProject(self, projectId):
        """ Returns an iterator over the all of the buildIds in a given
            project with ID projectId. The iterator is ordered by the date
            the associated group grove last changed in descending order
            (most to lease recent)."""

        cu = self.db.cursor()

        cu.execute("""SELECT buildId FROM Builds
                      WHERE projectId=? AND
                            troveName IS NOT NULL AND
                            troveVersion IS NOT NULL AND
                            troveFlavor IS NOT NULL AND
                            troveLastChanged IS NOT NULL
                            ORDER BY troveLastChanged DESC, buildId""",
                   projectId)

        for results in cu.fetchall():
            yield results[0]

    def setTrove(self, buildId, troveName, troveVersion, troveFlavor):
        cu = self.db.cursor()
        cu.execute("""UPDATE Builds SET troveName=?,
                                          troveVersion=?,
                                          troveFlavor=?,
                                          troveLastChanged=?
                      WHERE buildId=?""",
                   troveName, troveVersion,
                   troveFlavor, time.time(),
                   buildId)
        self.db.commit()
        return 0

    def setProductVersion(self, buildId, versionId, stageName):
        cu = self.db.cursor()
        cu.execute("""UPDATE Builds SET productVersionId=?,
                                          stageName=?,
                                          troveLastChanged=?
                      WHERE buildId=?""",
                   versionId, stageName,
                   time.time(), buildId)
        self.db.commit()

    def getTrove(self, buildId):
        cu = self.db.cursor()

        cu.execute("""SELECT troveName,
                             troveVersion,
                             troveFlavor
                      FROM Builds
                      WHERE buildId=?""",
                   buildId)
        r = cu.fetchone()

        name, version, flavor = r[0], r[1], r[2]
        if not flavor:
            flavor = "none"
        if not name or not version:
            raise TroveNotSet
        else:
            return name, version, flavor

    def getPublished(self, buildId):
        cu = self.db.cursor()
        cu.execute("SELECT COALESCE((SELECT pubReleaseId FROM Builds WHERE buildId=?), 0)", buildId)
        pubReleaseId = cu.fetchone()[0]
        if pubReleaseId:
            cu.execute("SELECT timePublished FROM PublishedReleases WHERE pubReleaseId = ?", pubReleaseId)
            res = cu.fetchone()
            if res:
                return bool(res[0])
        return False

    def getUnpublishedBuilds(self, projectId):
        cu = self.db.cursor()
        cu.execute("""SELECT buildId FROM Builds
                      WHERE projectId = ? AND pubReleaseId IS NULL""",
                      projectId)
        res = cu.fetchall()
        return [x[0] for x in res]

    def buildExists(self, buildId):
        cu = self.db.cursor()

        cu.execute("SELECT count(*) FROM Builds WHERE buildId=?", buildId)
        return cu.fetchone()[0]

    def bumpBuildCount(self, buildId):
        # This is a post-increment, unlike bumpCookCount, since we always want
        # to look at the last build.
        cu = self.db.cursor()
        cu.execute("SELECT buildCount FROM Builds WHERE buildId=?",
                   buildId)
        res = cu.fetchall()
        if res:
            count = res[0][0] + 1
            cu.execute("""UPDATE Builds
                              SET buildCount=?,
                              status=?,
                              statusMessage=?
                              WHERE buildId=?""", count, jobstatus.WAITING,
                              jobstatus.statusNames[jobstatus.WAITING],
                              buildId)
            return count
        else:
            return None

    @staticmethod
    def _filterBuildVisibility(rs, okHiddenProjectIds, limitToUserId):
        # admins see all
        if not limitToUserId:
            return True
        else:
            # restrict hidden projects unless you're a member
            if (not rs['isPrivate'] or (rs['isPrivate'] and (rs['projectId'] in okHiddenProjectIds))) and \
               (rs['isPublished'] or ((not rs['isPublished']) and (rs['role'] in ('Product Developer', 'Product Owner')))):
                return True
        return False

    def getAllBuildsByType(self, imageType, requestingUserId, 
                           limitToUserId=False):
        extraWhere = ''
        # by default, we organize builds by sha1.  This assumes
        # that builds have one file and that one file is the build.
        # not sure how to deal w/ error logs being associated since
        # we don't have an error status.
        extraSelect = ', bdf.sha1'
        extraJoin = ' LEFT JOIN buildFiles bdf ON (bdf.buildId = b.buildId)'
        if imageType == 'AMI':
            # cancel out sha1 join - we don't have any files with this build!
            extraJoin = ''

            # Extra selects:
            # add in awsAccount if it exists.
            extraSelect = ''', COALESCE(ud.value,'Unknown') AS awsAccountNumber,
                             bd.value AS amiId'''
            extraJoin += '''LEFT OUTER JOIN userData ud
                            ON (b.createdBy = ud.userId
                                AND ud.name = 'awsAccountNumber')'''

            # make sure that this build has an amiId.  Since it doesn't
            # have any files (thus no sha1), we need to know that it
            # has an amiId to know it uploaded correctly
            extraJoin += ''' JOIN buildData bd
                             ON (bd.buildId  = b.buildId
                                 AND bd.name = 'amiId')'''
        elif imageType == 'VWS':
            # VWS as a build type doesn't currently exist, but any
{'fraction_non_alphanumeric': 0.09067193118522174, 'fraction_numerical': 0.002397236127758584, 'mean_word_length': 1.5405695862439548, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 38, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6768529', 'n_tokens_mistral': 3682, 'n_tokens_neox': 3548, 'n_words': 1133}