Лучшие практики для модификации кода во время сборки муравья - PullRequest
6 голосов
/ 12 мая 2011

Признаюсь, это совсем не похоже на лучшую практику, но позвольте мне объяснить. Во время сборки нам нужно вставить номер сборки и системную версию в класс, единственная цель которого - содержать эти значения и сделать их доступными.

Нашей первой идеей было использование системных свойств, но из-за нестабильности среды развертывания (другой способ сказать, что «системные администраторы делают странные нечестивые жуткие вещи»), мы хотели бы, чтобы они были жестко запрограммированы.

По сути, я вижу 4 возможности достичь этого в муравье:

  1. использовать <replace> на токене в классе

    Проблема с этим подходом заключается в том, что файл изменяется, поэтому вы должны заменить токен после компиляции на <replaceregexp> ... ооочень, я не хочу касаться исходного кода с помощью регулярных выражений. Плюс временные зависимости.

  2. скопировать файл, произвести замену копии, скомпилировать копию, удалить копию

    Следует помнить о последовательности - сначала нужно скомпилировать исходный класс, чтобы перезаписать копию. Временные зависимости тоже безобразны.

  3. скопировать файл, заменить токен на оригинал, скомпилировать, заменить окрашенный оригинал копией

    Та же проблема временной зависимости, если она не включена в цель компиляции. Что тоже ужасно, потому что все наши файлы сборки используют одну и ту же импортированную цель компиляции.

  4. создать файл с нуля в скрипте сборки / сохранить файл вне исходного пути

    Улучшение по сравнению с первыми тремя, так как нет временных зависимостей, но компилятор / IDE очень недоволен, так как не замечает класс. Красные маркеры беспокоят ужасно.

Что вы думаете об альтернативах?

Есть ли лучшие практики для этого?

Уверен, я упустил совершенно нормальный подход.

Спасибо

EDIT В итоге мы использовали манифест для хранения номера сборки и версии системы в атрибуте Implementation-Version, unsing MyClass.class.getPackage().getImplementationVersion(). Я обнаружил, что это решение было одним из ответов на этой ветки , которая была размещена в комментарии от andersoj

Ответы [ 6 ]

10 голосов
/ 12 мая 2011

Я думаю, что более простым подходом было бы прочитать ваш класс Version.java из простого файла .properties, включенного в JAR, и просто сгенерировать этот файл .properties во время сборки в сборке Ant. Например, просто сгенерируйте:

build.number = 142
build.timestamp = 5/12/2011 12:31

Встроенная задача <buildnumber> в Ant уже делает половину этого (см. Второй пример).

2 голосов
/ 12 мая 2011

# 2, как правило, так я и делал, за исключением того, что ваши не готовые к компиляции источники должны располагаться отдельно от ваших готовых к компиляции источников. Это позволяет избежать временных проблем, о которых вы говорите, так как он должен быть скомпилирован только один раз.

Это общий шаблон, который все время проявляется в процессах сборки программного обеспечения.

Шаблон: Сгенерируйте источник из некоторого ресурса, а затем скомпилируйте его.

Это относится ко многим вещам - от фильтрации источников до компиляции до создания заглушек интерфейса для RMI, CORBA, веб-служб и т. Д. *

Скопируйте источник в указанное место 'сгенерированных источников' и выполните замену токена в файлах копий, чтобы сгенерировать источники, затем скомпилируйте сгенерированные источники в место назначения скомпилированных классов.

Порядок компиляции будет зависеть от того, зависят ли другие источники от сгенерированных источников.

1 голос
/ 12 мая 2011

Мое решение было бы:

  1. использовать на токене в классе:

    <replace dir="${source.dir}" includes="**/BuildInfo.*" summary="yes">
        <replacefilter  token="{{BUILD}}" value="${build}" />
        <replacefilter  token="{{BUILDDATE}}" value="${builddate}" />
    </replace>
    

Эта замена должна происходить только на этапах сборки, выполняемых вашей системой сборки, но не во время сеанса компиляции / отладки внутри IDE.

Настройка системы сборки в любом случае не должна отправлять измененный исходный код обратно в исходный репозиторий, поэтому проблема с измененным кодом не существует при таком подходе.

По моему опыту, это не помогает, когда вы помещаете информацию о сборке в файл свойств, поскольку администраторы, как правило, сохраняют файлы свойств при обновлении - заменяя файл свойств, который вышел из установки. (Информация о сборке в файле свойств является информационной для нас. Она позволяет во время запуска проверить, синхронизируется ли файл свойств с версией кода.)

0 голосов
/ 05 августа 2016

Я искал решение той же проблемы, читая эту ссылку: http://ant.apache.org/manual/Tasks/propertyfile.html Мне удалось найти решение.

Я работаю с NetBeans, поэтому мне просто нужно добавить этот кусок кода в свой build.xml

<target name="-post-init">
    <property name="header" value="##Generated file - do not modify!"/>
        <propertyfile file="${src.dir}/version.prop" comment="${header}">
            <entry key="product.build.major" type="int"  value="1" />
            <entry key="product.build.minor" type="int"  default="0" operation="+" />
            <entry key="product.build.date"  type="date" value="now" />
    </propertyfile>
</target>

Это будет увеличивать младшую версию каждый раз, когда вы компилируете проект с помощью clean и build. Таким образом, вы можете запустить проект в любое время, когда минорная версия останется на месте.

И мне просто нужно прочитать файл во время выполнения. Я надеюсь, что это поможет.

0 голосов
/ 12 мая 2011

Я всегда рекомендую создать какой-то каталог и поместить туда весь встроенный код. Не трогайте каталоги, которые вы проверили. Я обычно создаю каталог target и помещаю туда все файлы, модифицированные и построенные.

Если файлов * .java не слишком много (или файлов * .cpp), скопируйте их в target/source' and compile there. You can use thetask with a `, чтобы изменить этот файл на один файл с номером сборки при копировании.

<javac srcdir="${target.dir}/source"
    destdir="${target.dir}/classes"
    [yadda, yadda, yadda]
</java>

Таким образом, вы не вносите никаких изменений в извлеченный исходный каталог, поэтому никто не будет случайно проверять эти изменения. Кроме того, вы можете clean , просто удалив каталог target.

Если существуют тысячи, если не миллионы *.java файлов, вы можете скопировать шаблоны в target/source и затем скомпилировать исходные файлы как в {$basedir}/source, так и target/source. Таким образом, вы все равно не испортите извлеченный код и оставите шанс, что кто-то случайно проверит измененную версию. И вы все равно можете сделать clean, просто удалив target.

0 голосов
/ 12 мая 2011

Я помню, мы использовали 4-й подход немного по-другому. Вы можете передать номер релиза в скрипт ant при создании релиза. Скрипт Ant должен включать его в релиз (файл config / properties), и ваш класс должен прочитать его оттуда, возможно, используя файл свойств или файл конфигурации.

...