Вот странный пример, касающийся комбинации функций «define» и «include», которые предоставляет препроцессор CC.NET. Мы запускаем CCNet 1.4.4.83, и наш файл ccnet.config
структурирован и разделен, чтобы наилучшим образом использовать блоки общих элементов, хранящиеся в подфайлах, которые включены в основной файл конфигурации; мы также разделили основные определения проекта на их собственные включаемые файлы, оставив ccnet.config
как по существу серию включений, таким образом:
<cruisecontrol xmlns:cb="urn:ccnet.config.builder">
<!-- Configuration root folder - defined so we can use it as a symbol instead of using slightly confusing relative paths -->
<cb:define ccConfigRootFolder="C:\CruiseControl.NET\Config"/>
<!-- Globals - standard or shared build elements common to all projects -->
<cb:include href="$(ccConfigRootFolder)\Globals\globals.xml" xmlns:cb="urn:ccnet.config.builder"/>
<!-- CruiseControl.NET Configuration - refresh configuration if changed -->
<cb:include href="$(ccConfigRootFolder)\CCNet Configuration\ccnet_configuration.xml" xmlns:cb="urn:ccnet.config.builder"/>
<!-- Project #1 -->
<cb:include href="$(ccConfigRootFolder)\Project1\project1.xml" xmlns:cb="urn:ccnet.config.builder"/>
<!-- Project #2 -->
<cb:include href="$(ccConfigRootFolder)\Project2\project2.xml" xmlns:cb="urn:ccnet.config.builder"/>
</cruisecontrol>
Это работает, обработчик - препроцессор правильно включает и анализирует элементы <define>
в globals.xml
(и рекурсивно анализирует другие файлы, включенные и из globals.xml
), и проекты, включенные впоследствии (которые содержат ссылки на эти определенные элементы) правильно проанализированы.
Для дальнейшего уточнения ccnet.config
в попытке уменьшить вероятность ошибок, нарушающих процесс сборки, мы изменили его так:
<cruisecontrol xmlns:cb="urn:ccnet.config.builder">
<!-- Configuration root folder -->
<cb:define ccConfigRootFolder="C:\CruiseControl.NET\Config"/>
<!-- Project 'include' element definition -->
<cb:define name="ProjectInclude">
<cb:include href="$(ccConfigRootFolder)$(ccIncludePath)" xmlns:cb="urn:ccnet.config.builder"/>
</cb:define>
<!-- Include common gobal elements -->
<cb:ProjectInclude ccIncludePath="\Globals\globals.xml"/>
<!-- Project #1 -->
<cb:ProjectInclude ccIncludePath="\Project1\project1.xml"/>
<!-- Project #2 -->
<cb:ProjectInclude ccIncludePath="\Project2\project2.xml"/>
</cruisecontrol>
Как вы можете видеть, мы встроили общую, повторяющуюся часть определения 'include' в свой собственный определенный блок, а затем использовали его для каждого включения, используя путь в качестве параметра - идея заключается в том, что будущие модификаторы файл не будет иметь возможности случайно что-то забыть в своих новых включенных строках проекта (таких как URN препроцессора); до тех пор, пока существует их XML-файл и он правильно указывает путь к нему, об остальном позаботится общее определение включения.
Единственная проблема в том, что это не работает - по некоторым причинам, похоже, что файл globals.xml
не анализируется должным образом (или, возможно, даже не включается), потому что проекты, включенные после него, жалуются на отсутствие определенных элементов ; то есть ссылки на элементы, определенные в файле globals, по-видимому, «не зарегистрированы», потому что проекты их не распознают.
Мы попытались удалить вложенные включения из globals.xml
и включить их непосредственно на верхнем уровне, но безрезультатно. Закомментирование первой проблемной ссылки на элемент в проекте приводит к тому, что Validator жалуется на следующую, с сообщением «При предварительной обработке не удалось загрузить XML: ссылка на неизвестный символ XXXXX» . Однако если мы встраиваем тело globals.xml
в ccnet.config
, это работает. Как это ни странно звучит, как будто препроцессор совершенно не в состоянии анализировать globals.xml
, но затем счастливо прожирает файлы проекта, только чтобы потом потерпеть неудачу, потому что глобальные ссылки не определены.
Валидатор бездействует, если это так, однако. И, конечно, поскольку он не может правильно проанализировать проект XML, мы также ничего не получаем на вкладках «Оригинал» или «Обработано». Сама служба CruiseControl.NET не запускается с бесполезным исключением:
Служба не может быть запущена.
System.Runtime.Serialization.SerializationException:
Тип
'ThoughtWorks.CruiseControl.Core.Config.Preprocessor.EvaluationException'
в сборе
«ThoughtWorks.CruiseControl.Core,
Версия = 1.4.4.83, Культура = нейтральная,
PublicKeyToken = null 'не помечен как
сериализации. Трассировка стека сервера: в
System.Runtime.Serialization.Formatters.Binary.WriteObjectInfo.InitSerialize (Объект
obj, ISurrogateSelector
surrogateSelector, StreamingContext
контекст, SerObjectInfoInit
serObjectInfoInit, IFormatterConverter
конвертер, ObjectWriter (ObjectWriter)
в
System.Runtime.Serialization.Formatters.Binary.WriteObjectInfo.Serialize (Объект
obj, ISurrogateSelector
surrogateSelector, StreamingContext
контекст, SerObjectInfoInit
serObjectInfoInit, IFormatterConverter
конвертер, ObjectWriter (ObjectWriter)
в
System.Runtime.Serialization.Formatters.Binary.ObjectWriter.Serialize (Объект
graph, Header [] inHeaders,
__BinaryWriter serWriter, Boolean fCheck) в
System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Ser ...
Вся документация говорит, что это должно работать, и нет никаких упоминаний о какой-либо несовместимости или несоответствии при использовании «include» внутри «define».Так что я в замешательстве, и любое понимание или совет на этом этапе будут высоко оценены.