示例#1
0
    def bisect(self, good, bad, testcondition=None, args_for_condition=[]):
        #Call hg bisect with initial params, set up building environment (mozconfig)
        #Support for using dates
        if self.testBinaries:
            self.setupTests()

        badDate = re.search(r'(\d\d\d\d-\d\d-\d\d)', good)
        goodDate = re.search(r'(\d\d\d\d-\d\d-\d\d)', bad)
        if badDate != None and goodDate != None:
            badDate = badDate.group(1)
            goodDate = goodDate.group(1)
            good = self.changesetFromDay(
                goodDate)  #Get first changeset from this day
            bad = self.changesetFromDay(
                badDate, oldest=False)  #Get last changeset from that day

            if not (bad and good):
                print "Invalid date range."
                quit()

            #Since they entered dates, lets give them info about the changeset range
            print "Bisecting on changeset range " + str(
                good)[:12] + " to " + str(bad)[:12]

        #Get the actual changesets that we will be using
        good = hgId(good, self.hgPrefix)
        bad = hgId(bad, self.hgPrefix)

        if good and bad and self.validate(good, bad):
            #Valid changesets, so do the bisection
            subprocess.call(self.hgPrefix + ["bisect", "--reset"])

            setUpdate = captureStdout(self.hgPrefix + ["up", bad])
            setBad = captureStdout(self.hgPrefix + ["bisect", "--bad"])
            setGood = captureStdout(self.hgPrefix + ["bisect", "--good", good])

            print str(setUpdate)
            print str(setBad)
            print str(setGood)

            self.check_done(setGood)

            # Set mozconfig
            self.mozconfigure()

            # Call recursive bisection!
            self.bisectRecurse(testcondition=testcondition,
                               args_for_condition=args_for_condition)

        else:
            print "Invalid values. Please check your changeset revision numbers."
            print "If the problem persists, try running mozcommitbuilder with the -f flag."
示例#2
0
    def bisect(self,good,bad, testcondition=None, args_for_condition=[]):
        #Call hg bisect with initial params, set up building environment (mozconfig)
        #Support for using dates
        if self.testBinaries:
            self.setupTests()

        badDate = re.search(r'(\d\d\d\d-\d\d-\d\d)',good)
        goodDate = re.search(r'(\d\d\d\d-\d\d-\d\d)',bad)
        if badDate != None and goodDate != None:
            badDate = badDate.group(1)
            goodDate = goodDate.group(1)
            good = self.changesetFromDay(goodDate) #Get first changeset from this day
            bad = self.changesetFromDay(badDate, oldest=False) #Get last changeset from that day

            if not (bad and good):
                print "Invalid date range."
                quit()

            #Since they entered dates, lets give them info about the changeset range
            print "Bisecting on changeset range " + str(good)[:12] + " to " + str(bad)[:12]

        #Get the actual changesets that we will be using
        good = hgId(good, self.hgPrefix)
        bad = hgId(bad, self.hgPrefix)

        if good and bad and self.validate(good, bad):
            #Valid changesets, so do the bisection
            subprocess.call(self.hgPrefix+["bisect","--reset"])

            setUpdate = captureStdout(self.hgPrefix+["up",bad])
            setBad = captureStdout(self.hgPrefix+["bisect","--bad"])
            setGood = captureStdout(self.hgPrefix+["bisect","--good",good])

            print str(setUpdate)
            print str(setBad)
            print str(setGood)

            self.check_done(setGood)

            # Set mozconfig
            self.mozconfigure()

            # Call recursive bisection!
            self.bisectRecurse(testcondition=testcondition, args_for_condition=args_for_condition)

        else:
            print "Invalid values. Please check your changeset revision numbers."
            print "If the problem persists, try running mozcommitbuilder with the -f flag."
示例#3
0
    def getBinary(self, revision):
        #Create binary, put into cache directory.
        #Returns path of binary for a given changeset
        self.build(changeset=revision)

        #Run "make package"
        print "Making binary..."
        makeData = captureStdout(["make", "package"],
                                 ignoreStderr=True,
                                 currWorkingDir=os.path.join(
                                     self.repoPath, "obj-ff-dbg"))

        binary = None
        renamedBinary = None
        distFolder = os.path.join(self.repoPath, "obj-ff-dbg", "dist")
        #return path to package
        if sys.platform == "darwin":
            try:
                binary = glob.glob(distFolder + "/firefox-*.dmg")[0]
            except:
                binary = None
            renamedBinary = str(
                revision[:8]
            ) + ".dmg"  #Don't want the filename to be too long :)
        elif sys.platform == "linux2":
            try:
                binary = glob.glob(distFolder + "/firefox-*.tar.gz")[0]
            except:
                binary = None
            renamedBinary = str(revision[:8]) + ".tar.gz"
        elif sys.platform == "win32" or sys.platform == "cygwin":
            try:
                binary = glob.glob(distFolder + "/firefox-*.zip")[0]
            except:
                binary = None
            renamedBinary = str(revision[:8]) + ".zip"
        else:
            print "ERROR: This platform is unsupported."
            quit()

        if binary != None:
            print "Binary build successful!"
            print renamedBinary + " is the binary:"

            #Move the binary into the correct place.
            try:
                os.remove(os.path.join(self.shellCacheDir, renamedBinary))
            except:
                pass
            shutil.move(
                binary,
                os.path.join(self.shellCacheDir, "builds", renamedBinary))

            #Return binary path
            return (os.path.join(self.shellCacheDir, "builds",
                                 renamedBinary), renamedBinary)

        print "ERROR: Binary not found."
        quit()
示例#4
0
    def getBinary(self, revision):
        #Create binary, put into cache directory.
        #Returns path of binary for a given changeset
        self.build(changeset=revision)

        #Run "make package"
        print "Making binary..."
        makeData = captureStdout(["make","package"], ignoreStderr=True,
                                 currWorkingDir=os.path.join(self.repoPath,"obj-ff-dbg"))

        binary = None
        renamedBinary = None
        distFolder = os.path.join(self.repoPath,"obj-ff-dbg","dist")
        #return path to package
        if sys.platform == "darwin":
            try:
                binary = glob.glob(distFolder+"/firefox-*.dmg")[0]
            except:
                binary = None
            renamedBinary = str(revision[:8]) + ".dmg" #Don't want the filename to be too long :)
        elif sys.platform == "linux2":
            try:
                binary = glob.glob(distFolder+"/firefox-*.tar.gz")[0]
            except:
                binary = None
            renamedBinary = str(revision[:8]) + ".tar.gz"
        elif sys.platform == "win32" or sys.platform == "cygwin":
            try:
                binary = glob.glob(distFolder+"/firefox-*.zip")[0]
            except:
                binary = None
            renamedBinary = str(revision[:8]) + ".zip"
        else:
            print "ERROR: This platform is unsupported."
            quit()

        if binary != None:
            print "Binary build successful!"
            print renamedBinary + " is the binary:"

            #Move the binary into the correct place.
            try:
                os.remove(os.path.join(self.shellCacheDir,renamedBinary))
            except:
                pass
            shutil.move(binary, os.path.join(self.shellCacheDir,"builds",renamedBinary))

            #Return binary path
            return (os.path.join(self.shellCacheDir,"builds",renamedBinary), renamedBinary)

        print "ERROR: Binary not found."
        quit()
示例#5
0
    def build(self, changeset=0):
        #Build a binary and return the file path
        #Binary file named by changeset number
        if changeset != 0:
            changeset = str(changeset)
            print "Switching to revision "+changeset[:8]+"..."
            subprocess.call(self.hgPrefix+["update",changeset]) #switch to a given directory

        #Call make on our cached trunk
        print "Building..."
        makeData = captureStdout(self.makeCommand, ignoreStderr=True,
                                                        currWorkingDir=self.repoPath)
        if showMakeData == 1:
            print makeData

        print "Build complete!"
示例#6
0
    def build(self, changeset=0):
        #Build a binary and return the file path
        #Binary file named by changeset number
        if changeset != 0:
            changeset = str(changeset)
            print "Switching to revision " + changeset[:8] + "..."
            subprocess.call(
                self.hgPrefix +
                ["update", changeset])  #switch to a given directory

        #Call make on our cached trunk
        print "Building..."
        makeData = captureStdout(self.makeCommand,
                                 ignoreStderr=True,
                                 currWorkingDir=self.repoPath)
        if showMakeData == 1:
            print makeData

        print "Build complete!"
示例#7
0
    def bisectRecurse(self, testcondition=None, args_for_condition=[]):
        #Recursively build, run, and prompt
        verdict = ""
        current_revision = captureStdout(self.hgPrefix + ["id", "-i"])

        if self.remote:
            print "on current revision " + current_revision
            print "This would ask for a remote changeset, but it's not implemented yet."
            #TODO:
            #Remote bisection!
            #Step 1. Check if revision is in the archive
            #Step 2. If revision is not in the archive, set remote=False and continue (it will build and bisect that revision)
            #if not check_archived:
            #    set remote false and continue
            #else:
            #Step 3. If the revision is in the archive, download it and its corresponding tests
            #STEP3
            #1. Extract tests into some directory
            #2. Extract Nightly.app into "tests"
            #MozInstaller(src=, dest="", dest_app="Nightly.app")
            #3. run the following:
            #test_command = ['python', 'mochitest/runtests.py', '--appname=./Nightly.app/Contents/MacOS/firefox-bin', '--utility-path=bin', '--extra-profile-file=bin/plugins', '--certificate-path=certs', '--autorun', '--close-when-done', '--console-level=INFO', '--test-path=test_name']
            #output = captureStdout(test_command, ignoreStderr=True)
            #set verdict based on output
            #python mochitest/runtests.py --appname=./Nightly.app/Contents/MacOS/firefox-bin --utility-path=bin --extra-profile-file=bin/plugins --certificate-path=certs --autorun --close-when-done --console-level=INFO --test-path=test_name

            #example test name: Harness_sanity/test_sanityException.html
            #Step 4. Run and run test to get verdict
            #Step 5. Set verdict

        elif self.tryPusher:
            try:
                caller = BuildCaller(host=self.tryhost,
                                     port=int(self.tryport),
                                     data=current_revision)
                print "Getting revision " + current_revision + "..."
            except:
                print "Failed to connect to trypusher. Make sure your settings are correct and that the trypusher server was started."
                exit()
            response = caller.getChangeset()
            print "Waiting on Mozilla Pulse for revision " + response + "..."
            url = caller.getURLResponse(response)
            print "the base is " + url_base(url)
            #Download it here
            #1. Download from url, extract to same place as tests
            #2. Run test or start browser.
            binary_path = os.path.join(self.binaryDir, url_base(url))
            downloaded_binary = download_url(url, dest=str(binary_path))
            MozInstaller(src=str(binary_path),
                         dest=str(self.testDir),
                         dest_app="Nightly.app")
            #now nightly is installed in
            if sys.platform == "darwin":
                binary_path = os.path.join(self.testDir, "Nightly.app")
                runner = FirefoxRunner.create(
                    binary=os.path.join(binary_path, "Contents", "MacOS") +
                    "/firefox-bin")
            elif sys.platform == "linux2":
                binary_path = os.path.join(self.testDir, "firefox")
                runner = FirefoxRunner.create(binary=binary_path)
            elif sys.platform == "win32" or sys.platform == "cygwin":
                binary_path = os.path.join(self.testDir, "firefox.exe")
                runner = FirefoxRunner.create(binary=binary_path)
            else:
                print "Your platform is not currently supported."
                quit()

            dest = runner.start()
            if not dest:
                print "Failed to start the downloaded binary"
                verdict == "skip"
            runner.wait()
            if verdict == "skip":
                pass
            elif testcondition != None:
                #Support condition scripts where arg0 is the directory with the binary and tests
                args_to_pass = [self.testDir] + args_for_condition

                if hasattr(testcondition, "init"):
                    testcondition.init(args_to_pass)

                #TODO: refactor to use directories with revision numbers
                #8.2.11 - revision number can now be found in current_revision variable
                tmpdir = tempfile.mkdtemp()
                verdict = testcondition.interesting(args_to_pass, tmpdir)

                #Allow user to return true/false or bad/good
                if verdict != "bad" and verdict != "good":
                    verdict = "bad" if verdict else "good"
        else:
            try:
                self.build()
            except Exception:
                print "This build failed!"
                verdict = "skip"

            if verdict == "skip":
                pass
            elif testcondition == None:
                #Not using a test, interactive bisect begin!
                self.run()
            else:
                #Using Jesse's idea: import any testing script and run it as the truth condition
                args_to_pass = [self.objdir] + args_for_condition

                if hasattr(testcondition, "init"):
                    testcondition.init(args_to_pass)

                #TODO: refactor to use directories with revision numbers
                #8.2.11 - revision number can now be found in current_revision variable
                tmpdir = tempfile.mkdtemp()
                verdict = testcondition.interesting(args_to_pass, tmpdir)

                #Allow user to return true/false or bad/good
                if verdict != "bad" and verdict != "good":
                    verdict = "bad" if verdict else "good"

        while verdict not in ["good", "bad", "skip"]:
            verdict = raw_input(
                "Was this commit good or bad? (type 'good', 'bad', or 'skip'): "
            )
            if verdict == 'g':
                verdict = "good"
            if verdict == 'b':
                verdict = "bad"
            if verdict == 's':
                verdict = "skip"

        # do hg bisect --good, --bad, or --skip
        verdictCommand = self.hgPrefix + ["bisect", "--" + verdict]
        print " ".join(verdictCommand)
        retval = captureStdout(verdictCommand)

        string_to_parse = str(retval)
        print string_to_parse

        self.check_done(string_to_parse)

        if retval.startswith("Testing changeset"):
            print "\n"

        self.bisectRecurse(testcondition=testcondition,
                           args_for_condition=args_for_condition)
示例#8
0
    def bisectRecurse(self, testcondition=None, args_for_condition=[]):
        #Recursively build, run, and prompt
        verdict = ""
        current_revision = captureStdout(self.hgPrefix+["id","-i"])

        if self.remote:
            print "on current revision "+current_revision
            print "This would ask for a remote changeset, but it's not implemented yet."
            #TODO:
            #Remote bisection!
            #Step 1. Check if revision is in the archive
            #Step 2. If revision is not in the archive, set remote=False and continue (it will build and bisect that revision)
            #if not check_archived:
            #    set remote false and continue
            #else:
            #Step 3. If the revision is in the archive, download it and its corresponding tests
                #STEP3
                #1. Extract tests into some directory
                #2. Extract Nightly.app into "tests"
                #MozInstaller(src=, dest="", dest_app="Nightly.app")
                #3. run the following:
                #test_command = ['python', 'mochitest/runtests.py', '--appname=./Nightly.app/Contents/MacOS/firefox-bin', '--utility-path=bin', '--extra-profile-file=bin/plugins', '--certificate-path=certs', '--autorun', '--close-when-done', '--console-level=INFO', '--test-path=test_name']
                #output = captureStdout(test_command, ignoreStderr=True)
                #set verdict based on output
                #python mochitest/runtests.py --appname=./Nightly.app/Contents/MacOS/firefox-bin --utility-path=bin --extra-profile-file=bin/plugins --certificate-path=certs --autorun --close-when-done --console-level=INFO --test-path=test_name

                #example test name: Harness_sanity/test_sanityException.html
                #Step 4. Run and run test to get verdict
                #Step 5. Set verdict

        elif self.tryPusher:
            try:
                caller = BuildCaller(host=self.tryhost, port=int(self.tryport), data=current_revision)
                print "Getting revision "+current_revision+"..."
            except:
                print "Failed to connect to trypusher. Make sure your settings are correct and that the trypusher server was started."
                exit()
            response = caller.getChangeset()
            print "Waiting on Mozilla Pulse for revision " + response + "..."
            url = caller.getURLResponse(response)
            print "the base is " +url_base(url)
            #Download it here
            #1. Download from url, extract to same place as tests
            #2. Run test or start browser.
            binary_path =  os.path.join(self.binaryDir,url_base(url))
            downloaded_binary = download_url(url, dest=str(binary_path))
            MozInstaller(src=str(binary_path), dest=str(self.testDir), dest_app="Nightly.app")
            #now nightly is installed in
            if sys.platform == "darwin":
                binary_path = os.path.join(self.testDir,"Nightly.app")
                runner = FirefoxRunner(binary=os.path.join(binary_path,"Contents","MacOS")+"/firefox-bin")
            elif sys.platform == "linux2":
                binary_path = os.path.join(self.testDir,"firefox")
                runner = FirefoxRunner(binary=binary_path)
            elif sys.platform == "win32" or sys.platform == "cygwin":
                binary_path = os.path.join(self.testDir,"firefox.exe")
                runner = FirefoxRunner(binary=binary_path)
            else:
                print "Your platform is not currently supported."
                quit()

            dest = runner.start()
            if not dest:
                print "Failed to start the downloaded binary"
                verdict == "skip"
            runner.wait()
            if verdict == "skip":
                pass
            elif testcondition!=None:
                #Support condition scripts where arg0 is the directory with the binary and tests
                args_to_pass = [self.testDir] + args_for_condition

                if hasattr(testcondition, "init"):
                    testcondition.init(args_to_pass)

                #TODO: refactor to use directories with revision numbers
                #8.2.11 - revision number can now be found in current_revision variable
                tmpdir = tempfile.mkdtemp()
                verdict = testcondition.interesting(args_to_pass,tmpdir)

                #Allow user to return true/false or bad/good
                if verdict != "bad" and verdict != "good":
                    verdict = "bad" if verdict else "good"
        else:
            try:
                self.build()
            except Exception:
                print "This build failed!"
                verdict = "skip"

            if verdict == "skip":
                pass
            elif testcondition==None:
                #Not using a test, interactive bisect begin!
                self.run()
            else:
                #Using Jesse's idea: import any testing script and run it as the truth condition
                args_to_pass = [self.objdir] + args_for_condition

                if hasattr(testcondition, "init"):
                    testcondition.init(args_to_pass)

                #TODO: refactor to use directories with revision numbers
                #8.2.11 - revision number can now be found in current_revision variable
                tmpdir = tempfile.mkdtemp()
                verdict = testcondition.interesting(args_to_pass,tmpdir)

                #Allow user to return true/false or bad/good
                if verdict != "bad" and verdict != "good":
                    verdict = "bad" if verdict else "good"

        while verdict not in ["good", "bad", "skip"]:
            verdict = raw_input("Was this commit good or bad? (type 'good', 'bad', or 'skip'): ")
            if verdict == 'g':
                verdict = "good"
            if verdict == 'b':
                verdict = "bad"
            if verdict == 's':
                verdict = "skip"

        # do hg bisect --good, --bad, or --skip
        verdictCommand = self.hgPrefix+["bisect","--"+verdict]
        print " ".join(verdictCommand)
        retval = captureStdout(verdictCommand)

        string_to_parse = str(retval)
        print string_to_parse

        self.check_done(string_to_parse)

        if retval.startswith("Testing changeset"):
            print "\n"

        self.bisectRecurse(testcondition=testcondition, args_for_condition=args_for_condition)
示例#9
0
    def bisectRecurse(self, testfile=None, testpath=None, testcondition=None, args_for_condition=[]):
        #Recursively build, run, and prompt
        verdict = ""

        try:
            self.build()
        except Exception:
            verdict = "skip"

        if verdict == "skip":
            pass
        elif testfile==None and testpath==None and testcondition==None:
            #Not using a test, interactive bisect begin!
            self.run()
        elif testcondition != None:
            #Using Jesse's idea: import any testing script and run it as the truth condition
            conditionscript = ximport.importRelativeOrAbsolute(testcondition)
            args_to_pass = [self.objdir] + args_for_condition
            conditionscript.init(args_to_pass)

            #TODO: refactor to use directories with revision numbers
            tmpdir = tempfile.mkdtemp()

            #If conditionscript is true, that means there was a bug.
            #If conditionscript is false, that means the bug is not present.
            verdict = conditionscript.interesting(args_to_pass,tmpdir)
            verdict = "bad" if verdict else "good"
        else:
            if testfile == None:
                #Using External testfile
                #1. Clear self.mochitest_tmp
                try:
                    shutil.rmtree(self.mochitest_tmp)
                except:
                    pass
                #2. Move file from testpath to self.mochitest_tmp
                try:
                    os.mkdir(self.mochitest_tmp)
                    dst =  os.path.join(self.mochitest_tmp,"test_bug999999.html")
                    subprocess.call(['touch',dst])
                    print "copy " + str(testpath) + " to " +dst
                    shutil.copy(str(testpath),dst)
                except:
                    print "Unable to generate test path, quitting. Is your inputted test a valid mochitest?"
                    quit()
                #3. Make mochitest use the commitbuilder directory.
                testfile="commitbuilder"

            #DEBUG
            #testfile = "content/base/test/test_CrossSiteXHR.html"

            print "Trying testfile "+str(testfile)
            #TODO:
            # 1. Copy relevant test to a directory of my choice


            #sts = os.system("TEST_PATH="+testpath+" EXTRA_TEST_ARGS='--close-when-done' make -C " +self.objdir+ " mochitest-plain")
            sts = subprocess.call(['make','-C',self.objdir,'mochitest-plain'],stdout=open('/dev/null','w'),env={'TEST_PATH': testfile, 'EXTRA_TEST_ARGS':"--close-when-done"})
            shutil.rmtree(self.mochitest_tmp) #cleanup
            if sts != 0:
                verdict = "bad"
                print "============================"
                print "Verdict: FAILED test, bad changeset detected!"
                print "============================"
            else:
                verdict = "good"
                print "============================"
                print "Verdict: PASSED test, good changeset detected!"
                print "============================"

        while verdict not in ["good", "bad", "skip"]:
            verdict = raw_input("Was this commit good or bad? (type 'good', 'bad', or 'skip'): ")

        # do hg bisect --good, --bad, or --skip
        verdictCommand = self.hgPrefix+["bisect","--"+verdict]
        print " ".join(verdictCommand)
        retval = captureStdout(verdictCommand)
        print str(retval)

        # HACK
        if retval[1] == 'h': #if retval starts with "the" then we can quit
            quit()
        elif retval[1] == 'e': #if retval starts with "testing" then it needs to keep going
            print "\n"
        else:
            print "Something went wrong! :("
            quit()

        self.bisectRecurse(testfile=testfile, testpath=testpath, testcondition=testcondition, args_for_condition=args_for_condition)