def link_project(self, mproject):
     """
     Loads in the commits from a project and then attempts to place new entires in the
     user_corporation_project table (aka ProjectInvolvement) table.
     
     @param mproject: a dbobjects.MasterProject element to load the data for
     """
     # FIXME: this currently has no support for hierarchical master projects
     projects = Project.select(Project.q.masterProjectID == mproject.id) # pylint: disable-msg=E1101
     
     # we'll need this for building SQL queries
     projarr = [x.id for x in projects]
     
     # get the first commit on the project so we know what month to start pumping data at
     firstcommit = CVSCommit.select(AND(CVSCommit.q.startDate > datetime.datetime(1997, 11, 01), # pylint: disable-msg=E1101
                                        IN(CVSCommit.q.projectID, projarr))).min(CVSCommit.q.startDate) # pylint: disable-msg=E1101
                                        
     lastcommit = CVSCommit.select(AND(CVSCommit.q.startDate > datetime.datetime(1997, 11, 01), # pylint: disable-msg=E1101
                                       IN(CVSCommit.q.projectID, projarr))).max(CVSCommit.q.startDate) # pylint: disable-msg=E1101
     if firstcommit == None:
         # do something here to indicate that it couldn't process this time period
         self.log.info("Project %s (id=%s) does not appear to have any commits in the window", mproject.name, mproject.id)
         return
                                    
     self.log.info("%s - %s %s", mproject.name, firstcommit, lastcommit)
     
     # iterate on a monthly basis across the data so we have monthly snapshots, just as we do for Eclipse
     currentdate = datetime.datetime(firstcommit.year, firstcommit.month, 1)
     nextdate = add_month(currentdate)
     while currentdate < lastcommit:
         self.link_project_month(mproject, projarr, currentdate, nextdate)
         currentdate = nextdate
         nextdate = add_month(currentdate)
 def link_project_month(self, mproject, projarr, currentdate, nextdate):
     """
     Does the "heavy" lifting for linking individuals to projects over a time period
     
     @param mproject: master project to link to
     @param projarr: the array of child projects
     @param currendate: the date to start looking
     @param nextdate: the date to stop looking
     """
     # get the developers who committed during that period
     people = Person.select(AND(Person.q.id == PersonUser.q.personID, # pylint: disable-msg=E1101
                                PersonUser.q.userID == CVSCommit.q.userID, # pylint: disable-msg=E1101
                                CVSCommit.q.startDate >= currentdate, # pylint: disable-msg=E1101
                                CVSCommit.q.startDate < nextdate, # pylint: disable-msg=E1101
                                IN(CVSCommit.q.projectID, projarr)), distinct=True) # pylint: disable-msg=E1101
     
     count = 0
     numcorp = 0
     numunknown = 0
     # iterate over each of the people
     for person in people:
         user = User.select(AND(User.q.id == PersonUser.q.userID, # pylint: disable-msg=E1101
                                PersonUser.q.personID == person.id))[0] # pylint: disable-msg=E1101
             
         # first get their company.  cache it if possible
         if self.corpmap.has_key(person.id):
             corporation = self.corpmap[person.id]
         else:
             corporations = person.corporations
             if len(corporations) == 0:
                 corporation = self.unknowncorp
             else:
                 corporation = corporations[0]
             self.corpmap[person.id] = corporation
         
         # increment some tracking counters
         if corporation == self.unknowncorp:
             numunknown = numunknown + 1
         else:
             numcorp = numcorp + 1
             
         # now, get their commits, we need the number of commits and the number of lines added/removed
         commits = CVSCommit.select(AND(CVSCommit.q.userID == PersonUser.q.userID, # pylint: disable-msg=E1101
                                     PersonUser.q.personID == person.id, # pylint: disable-msg=E1101
                                     CVSCommit.q.startDate >= currentdate, # pylint: disable-msg=E1101
                                     CVSCommit.q.startDate < nextdate, # pylint: disable-msg=E1101
                                     IN(CVSCommit.q.projectID, projarr)), distinct=True) # pylint: disable-msg=E1101
         commitids = [x.id for x in commits]
         numcommits = len(commitids)
         
         # in some cases, we don't have complete information, we just set those to empty here
         linesadded = FileCommit.select(IN(FileCommit.q.cvsCommitID, commitids)).sum(FileCommit.q.linesAdded) or 0 # pylint: disable-msg=E1101
         linesremoved = FileCommit.select(IN(FileCommit.q.cvsCommitID, commitids)).sum(FileCommit.q.linesRemoved) or 0 # pylint: disable-msg=E1101
         linesdelta = linesadded - linesremoved
         
         # commit the object
         newpi = ProjectInvolvement(user=user, corporation=corporation,
                                    project=mproject, year=currentdate.year,
                                    month=currentdate.month, date=currentdate,
                                    numCommits=numcommits, linesAdded=linesadded,
                                    linesRemoved=linesremoved, linesDelta=linesdelta)
         count = count + 1
     self.log.info("%s-%s Added %d links (%d corp, %d unknown)...", currentdate, nextdate, count, numcorp, numunknown) 
     return count