[CMake] CTEST_UPDATE_COMMAND vs sparse working copy (was Re: continuous integration with CMake)

Tyler Roscoe tyler at cryptio.net
Mon Mar 22 13:35:53 EDT 2010


Following up on this thread:
http://public.kitware.com/pipermail/cmake/2010-February/035197.html

It's not as elegant as I would like -- support for ctest_update(...
APPEND ...) would be much cleaner, but I didn't have the bandwidth to
take on that project at this time -- but I believe I have a hack to
solve my problem. 

This hack violates one of my fundamental rules: Thou Shalt Not Parse XML
With Regular Expressions, but I decided that a "native" CTest solution
would be easier to work with than an external python script using a
python XML module.

I'm posting this here in case it's helpful to someone else. Improvements
and bug fixes are also welcome of course :).

This is just a snippet from our CTest script that is driving Continuous
builds. Some stuff may be missing (because it's defined elsewhere). Let
me know if there's anything inscrutable and I'll fill it in.

Oh yeah, thanks again to Clinton for the hack where we read the TAG file and
use that to figure out where CTest is writing its .xml files.

Thanks,
tyler



[...]

# Used by tp_update().
set (TP_CTEST_UPDATE_XML_FILE "Update.xml")

[...]

    # Start a new submission.
    ctest_start (${dashboard_model})
    # Calculate TP_CTEST_XML_DIR (which changes whenver ctest_start() is called).
    file (READ "${CTEST_BINARY_DIRECTORY}/Testing/TAG" tag_file)
    string (REGEX MATCH "[^\n]*" xml_dir ${tag_file})
    set (TP_CTEST_XML_DIR "${CTEST_BINARY_DIRECTORY}/Testing/${xml_dir}")

[...]

# ctest_update() does not work well with sparse working copies (and doesn't
# support APPEND) so we work around that by hacking together the XML files
# ctest_update() generates for CDash.
macro (tp_update)
    unset (final_update_xml_contents)
    set (count 0)

    # tmr: RACE CONDITION HERE!!! maybe try to compensate by storing latest
    # revision at time of first update. but with no way to pass this value
    # to the svn st/svn info commands issued by ctest, not sure if it would
    # help.
    #
    # A test to enforce a quiet period in the repo before starting a build
    # could also solve this problem.
    foreach (subproject ${TP_SUBPROJECTS})
        ctest_update (
            SOURCE "${CTEST_SOURCE_DIRECTORY}/${subproject}/${TP_BRANCH}"
            RETURN_VALUE subproject_count
        )
        message ("Found ${subproject_count} changed files in subproject ${subproject}/${TP_BRANCH}")
        math (EXPR count "${subproject_count} + ${count}")

        if (subproject_count GREATER 0)
            # Because we run a separate ctest_update() in each subproject
            # directory, we have to prepend ${subproject}/${TP_BRANCH} to the paths
            # returned by Subversion.
            #
            # tmr: Need to do anything (get rid of trailing slash?) when the
            # Update.xml contains an empty "<Name></Name>"?
            file (READ
                "${TP_CTEST_XML_DIR}/${TP_CTEST_UPDATE_XML_FILE}"
                update_xml_contents
            )
            #message ("%%%%% raw update_xml_contents: ${update_xml_contents}")

            # Quotes around input variable are required! Without them, CMake
            # gets confused about semicolons (like the one in the XML entity
            # '&quot;'), resulting in malformed XML which CDash silently
            # drops.
            string (REPLACE
                "<Name>"
                "<Name>${subproject}/${TP_BRANCH}/"
                massaged_xml_contents
                "${update_xml_contents}"
            )
            string (REPLACE
                "<Directory>"
                "<Directory>${subproject}/${TP_BRANCH}/"
                massaged_xml_contents
                "${massaged_xml_contents}"
            )
            string (REPLACE
                "<FullName>"
                "<FullName>${subproject}/${TP_BRANCH}/"
                massaged_xml_contents
                "${massaged_xml_contents}"
            )
            #message ("%%%%% massaged_xml_contents: ${massaged_xml_contents}")

            # If this is the first XML file we're processing, we want to
            # keep the preamble.
            if (NOT DEFINED final_update_xml_contents)
                # tmr: Add comment that this Update.xml has been manually
                # cobbled together by this script.
                #set (final_update_xml_contents "<!-- comment -->")
                string (REGEX REPLACE
                    "<Directory>.*"
                    ""
                    final_update_xml_contents
                    "${massaged_xml_contents}"
                )
            #message ("%%%%% final_update_xml_contents (should just contain preamble now): ${final_update_xml_contents}")
            endif ()

            # Pull out the body and save it.
            string (REGEX REPLACE
                ".*</UpdateType>[\r\n]+"
                ""
                xml_body
                "${massaged_xml_contents}"
            )
            string (REGEX REPLACE
                "<EndDateTime>.*"
                ""
                xml_body
                "${xml_body}"
            )
            set (final_update_xml_contents "${final_update_xml_contents}${xml_body}")
            #message ("%%%%% final_update_xml_contents (should contain preamble + some bodies): ${final_update_xml_contents}")
        endif ()
    endforeach ()

    # Finally, grab the postamble from the last XML file we processed (if
    # any) and save it.
    if (DEFINED final_update_xml_contents)
        string (REGEX REPLACE
            ".*<EndDateTime>"
            "<EndDateTime>"
            xml_postamble
            "${massaged_xml_contents}"
        )
        set (final_update_xml_contents "${final_update_xml_contents}${xml_postamble}")
        #message ("%%%%% final_update_xml_contents (final): ${final_update_xml_contents}")

        # Replace the last Update.xml with the massaged Update.xml.
        file (REMOVE "${TP_CTEST_XML_DIR}/${TP_CTEST_UPDATE_XML_FILE}")
        file (WRITE "${TP_CTEST_XML_DIR}/${TP_CTEST_UPDATE_XML_FILE}" "${final_update_xml_contents}")
    endif ()
endmacro ()



More information about the CMake mailing list