После не самого удачного, на мой взгляд, эксперимента по сборке flex с использованием maven (подробности тут), решил попробовать gradle, про который пишут, что он взял лучшее от ant и maven и это следующий шаг в развитии. Решил провести эксперимент по такому плану:
- flex compile (Path to FlexSDK/maven dependency)
- as3 compile
- flex unit run (dependency)
- fla compile as static resource
- reliase compress
- code quality (FlexPMD)
- multy module project
Кому интересно, что из этого получилось, прошу под кат, потому как текста достаточно много. Он писался прямо по ходу эксперимента, если читать совсем лень, то в конце есть ссылка на тестовый проект.
Установка Gradle и первые впечатления.
Раззипуй — скопируй + Gradle_Home/bin в общий Path. Без затей абсолютно. Хорошая подсказка в коммандной строке, даже с цветом.
D:ProjectsGradleFlexTest>gradle tasks
:tasks
------------------------------------------------------------
All tasks runnable from root project
------------------------------------------------------------
Build Setup tasks
-----------------
setupBuild - Initializes a new Gradle build. [incubating]
Help tasks
----------
dependencies - Displays all dependencies declared in root project 'GradleFlexTest'.
dependencyInsight - Displays the insight into a specific dependency in root project 'GradleFlexTest'.
help - Displays a help message
projects - Displays the sub-projects of root project 'GradleFlexTest'.
properties - Displays the properties of root project 'GradleFlexTest'.
tasks - Displays the tasks runnable from root project 'GradleFlexTest' (some of the displayed tasks may belong to subprojects).
To see all tasks and more detail, run with --all.
BUILD SUCCESSFUL
Для начального понимания, как это все работает, можно прочитать начальные главы user guide, примерно до 9 главы. Этого вполне достаточно, чтобы осознать базовые принципы работы системы.
У командной строки есть user friendly gui для нелюбителей консоли: gradle --gui
Заметки
- При использовании командной строки, в папке запуска gradle создает свою временную папку .gradle, куда складывает временные артефакты работы. Папка не большая, но после экспериментов ее бы лучше удалить или заигнорить в гите.
- При запуске gui, в папке запуска создается файл дополнительных настроек. Думаю, действовать по аналогии с первым.
- При попытке тестового билда пустой папки создается файл билда build.gradle с настройками по умолчанию. Мелочь, а приятно.
Flex проект
Flex пока не входит в основную документацию и примеров по нему в поставке нет. Это как бы понятно, хотя, конечно, жаль, потому как остальных примеров достаточно много. Но, беглый просмотр плагинов обрадовал наличием признанного плагина для flex — GradleF. С него и начнем.
GradleFX
На первый взгляд, проект неплохо документирован, хотя только смелый эксперимент покажет насколько именно.
Первая радость: плагин есть в центральном maven репозитории. Оттуда узнаю его последнюю версию ее и буду пробовать.
Вторая радость: есть больше одного варианта указать, с каким именно FlexSDK будет работать проект. Есть стандартный FLEX_HOME, прямое указание пути на локальном диске и зависимости. Последний путь мне нравится больше всего, как наиболее универсальный.
Итак, определяю тип проекта как swf, беру зависимость от Apach Flex SDK (потому как раньше ее не пробовал) и определяю путь к зипу автоустновки flex sdk (отличная фича, с учетом отсутствия flex sdk в репозиториях).
Первый запуск
Поскольку кроме build.gradle ничего нет, то на выходе получил fail, но это ожидаемо. Что же произошло еще исходя из лога (сам лог не выкладываю, уж больно большой)?
- В домашней директории появилась папка .gradle, которая является локальных хранилищем артефактов. Сюда, скорее всего, будет складываться все, что будет скачано.
- Загрузился плагин GradleFX из центрального maven репозитория и разместился по .gradlecachesartifacts-24filestoreorg.gradlefxgradlefx.6.4 (судя по всему, все загрузки попадают в .gradlecachesartifacts-24filestore, вроде больше мест не нашел)
- Загрузился и распаковался ahache flex sdk
- Загрузился swf-object, swfobject-fabridge, osmf, спросили про лицензию на osmf, blase-ds, adobe flex sdk
Загрузилось, несколько больше, чем я рассчитывал, например adobe flex sdk мне не очень понятен, возможно это зависимость чего-то. Дважды спрашивали, согласен ли я загрузить чего-то, может оттуда и ноги растут. Но тем не менее, это можно считать удачей, потому как требуемые компоненты найдены.
Scaffold и первый build.
Плагин scaffold — генерация типового проекта. По большому счету, это разовая акция, но почему бы не попробовать, раз уж она все равно есть. На текущий мометн scaffold имеет всего одну задачу — создать типовой проект.
gradle scaffold
Как и ожидалось, создана структура папок и main.mxml файл заглушка. Пробую сделать первый билд из того, что получилось.
Первая особенность Очень долгая обработка Air SDK, при вызове любой задачи, даже gradle tasks
, идет его раззиповка, а это явно лишнее. Возможно, это моя ошибка, я включил обе зависимости от flex и от air. Пробую убрать air, как не сильно нужную прямо сейчас. Оказывается, я не сильно внимательно прочитал документацию, там прямо сказано, что распаковка sdk зависит от типа результата, но происходит в одну и ту же папку. Это может означать, что при работе поочередно с различными типами проектов (air/flex) будет происходить раззиповка необходимого sdk. Если тип проекта не менялся, то повторной раззиповки происходить не должно.
Итак, первый билд провалился, второй завершился удачно. Что же было? Имея две зависимости, одна из которых исключает
вторую получили:
- авто установка flex sdk
- авто установка air sdk (именно отсюда бралась длительная раззиповка)
- фактический билд main.mxml с помощью последней (air) установленной sdk
- результат — fail — не найден файл конфигурации, что достаточно логично.
Убираю air-зависимость и пробую собрать еще раз. Собрано. Получаю папку build, в которой лежит флеха и ее сопутствующие компоненты. Вторая раззиповка не произошла, все в порядке.
Заметки
- Gralde постоянно выводит предупреждения, которые должны попасть к разработчику плагина: некоторые методы помечены как deprecated, в версии 2 (текущая 1.6) они будут удалены, используйте вместо них другие. Меня всегда радовали такие сообщения. Предупреждение гораздо приятнее, чем сразу удаление методов. К тому же, сразу указан новый путь. Явный плюс разработчикам gradle.
- Этот эксперимент полностью объясняет лишние скачки, которые меня удивили в логе. Если air sdk зависит от adobe flex sdk, что в общем логично, то он дополнительно и скачался. Как вывод — читать внимательнее и иногда думать. Это бывает полезно.
Сравнение времени сборки (сек.)
build | gradle | maven | idea |
---|---|---|---|
1 | 12.031 | 12.172 | 13 |
2 | 6.25 | 7.63 | 4 |
Хотел еще сравнить с FlashDevelop, но он не выводит время сборки. Выигрыш IDEA скорее всего основан на одноразовой загрузке конфигурации, при первом билде проекта.
As3 compile
Пробую перевести проект чистый as3. Можно еще отключить scaffold, но он вроде не мешает, хоть пока и больше не нужен. Наличие данного плагина не влияет на скорость сборки, возможно чуть больше памяти занимает. Итак, меняю Main.mxml на Main.as. Билд не проходит. Совершенно по честному говорит, что Main.mxml не найден. Смотрю документацию и нахожу свойство, которое отвечает за точку входа. Это mainClass
. Логичнее трудно придумать. Задаем новое значение — build success! Этап pure as3 project пройден.
Заметка Для чистого as3 проекта имеет смысл указать frameworkLinkage='none'
, т.е. не линковать flex во флеху (-200 б примерно).
Flex unit tests.
Добавляю класс заглушку и тест, который его проверяет. Аналогично maven, необходимо определить местонахождение дебажного FashPlayer. Опять же, можно использовать системную переменную FLASH_PLAYER_EXE или задать flexUnit.command
напрямую. Использую последний метод, как более явный (ну не люблю я использовать системные переменные). Тем более, что при желании, это можно вынести в свойства и использовать аналогично профилям maven.
Добавляю требуемые зависимости. Небольшой затык, как обычно, в репозитории. FlexUnit не поддерживает свой репозиторий и в публичные не выкладывает, по крайней мере официально. В документации GradleFX настоятельно рекомендуется разворачивать свой репозиторий, но пока что-то не сильно хочется.
Интересно Есть интересная ссылка на сервер CI можно посмотреть, как собирается этот проект.
Внимание В документации опечатка в зависимости для flexunit-tasks — расширение 'jar', а не 'swc'. В примере файловой зависимости написано правильно.
FlexUnit в GradleXF работает через Ant-овский flexunit-tasks. Это не совсем тот сюрприз, который бы я хотел видеть, но с другой стороны, зачем дублировать функционал? Проблема в том, что этого файла нет в репозиториях, а сам GradleFX есть. Некоторый поиск показал отсутствие файла flexUnitTasks-4.1.0-8.jar в публичных репозиториях. Это опять подталкивает к развертыванию своего. Но, для запуска unit тестов надо три зависимости: сам flexunit, flexunit-tasks (ant часть), flexunit-cilistener для связи между ними. Как-то много для простого теста. Поэтому беру файловую зависимость из примера.
gradle test
Вполне удачное завершение.
Заметка для Win пользователей Все пути определяются через `/`, а не через ``, как все привыкли под виндой. На эту ошибку вежливо укажет вывод командной строки, чем здорово сократит время ее поиска. Командная строка радует все больше, пока самая информативная из тех, что я видел.
Сравнение времени выполнения тестов (сек.)
build | gradle | maven | idea |
---|---|---|---|
1 | 31.061 | 37.891 | 13 |
2 | 14.75 | 17.516 | 7 |
Для IDEA точное время сказать сложно, суммарно оно не выводится. Сосчитал по логу. Первый запуск: 10 сборка + 3 тесты. Правда фактическое время выполнения указано, как 1,56 с. Но по логу завершилось на 1,5 позже. Второй запуск: 5 сборка + 2 тесты. Фактическое время опять меньше 1,5. Но в любом случае IDEA пока лидер по скорости.
Фактически, использовать unit тестирование удалось. Но есть одна неприятность — файл билда стал непортируемым, т.е. зависимым от абсолютных путей, плюс достаточно большая подготовка для первого запуска. Хочется избавиться от этого недостатка и добавить возможность автоустновки зависимостей flexunit аналогично flex sdk. Поскольку я не знаток groovy (вообще не знаю), то попробую сделать это на примере автоустановки flex sdk. Порывшись в примерах и исходных кодах GradleFX, собрал небольшое дополнение, которое скачивает при необходимости зависимости для unit-тестирования. Код, конечно, изяществом не блещет, но, для первого раза, наверно не плохо. При этом возможность стандарной настройки через системные переменные сохранилась.
Первый запуск удлиннился (самый первый) до 3 минут (в основном за счет скачивания flexunit — очень медленный процесс), но второй вернулся на старые 14 секунд.
Fla как статический ресурс
Сделаю небольшую fla библиотеку ресурсов и попытаюсь ее собрать в swc перед компиляцией. Как продолжение привета от Adobe, jsfl скрипты не могут принимать параметры из командной строки. Значит придется частично скрипт генерить. По факту, скрипт будет запускаться в Flash CS, и, хочется того или нет, но он должен быть открыт (если нет, то все равно откроется, только дольше это будет). Для генерации я использую метод fl.publishDocument
, который как бы не открывает fla, а публикует его в тихом режиме. Ходят слухи, что это быстрее и не течет память. Как обычно, первая компиляция самая медленная, потом достаточно быстро. Вопрос, что будет если fla будет много, остается открытым.
Заметка Adobe ExtendScript Toolkit, родной редактор для jsfl скриптов от Adobe близок по удобству к CS action editor, те. сделан для крепких духом людей. Попробовал и забыл как страшный сон.
Пробую пристегнуть этот скрипт к существующему билду. Несколько надоело писать в блокноте, пробую импортировать проект в IDEA и писать там. Импорт прошел хорошо, все задачи видно и они выполняются. Но по умолчанию после импорта, писать buid.gradle практически точно так же, как в блокноте. Я надеялся на более широкую поддержку. Когда не знаешь языка — автокомплит был бы очень кстати.
Пробую второй путь, возможно разработчики GradleFX предусмотрели, что-то более глобальное для IDEA. Для этого использую плагин IDE plagin.
gradle idea
:scaffold
Creating directory structure
src/main/actionscript
src/main/resources
src/test/actionscript
src/test/resources
Main class already exists
src/main/actionscript/
:idea
Verifying project properties c
Creating IntelliJ IDEA project
:idea FAILED
FAILURE: Build failed with an
* What went wrong:
Execution failed for task ':id
> TODO implement IdeaProject
Упс, оказывается эта задача не реализована… Ну и ладно, с такой поддержкой синтаксиса и AkelPad отлично справляется.
Общие понятия о groovy все-таки придется изучить (для типовых проектов, можно обойтись примерами из документации), если хочется сделать что-то свое. Кстати, есть неплохая статья на Хабре Groovy за 15 минут.
Сюрпризы продолжаются, fileUri не всеми понимается одинаково, как неожиданно выяснилось.
Adobe jsfl fileUri file:///d|/Projects/GradleFlexTest/src/main/fla/
Groovy fileUri file:/D:/Projects/GradleFlexTest/src/main/fla/
Со вторым типом CS не работает, но и не падает. Просто ничего не происходит. После некоторого погружения в гугл и вывод консоли, собралась задача для сборки fla файлов в swc (с некоторыми органичениями). По большому счету, остался один абсолютный путь. Это CS. Врядли это большая проблема, установить его автоматически невозможно, а пути установки более менее стандартны. Буду считать это договоренностью.
Заметки
- CS можно прописать в PATH, тогда cmd сможет напрямую выполнять jsfl скрипты.
- Посмотрел примеры ant по запуску через командную строку. Оказывается можно избавиться от абсолютного пути к CS.
- Задачи билда надо определять, как
task flaBuild << { ... }
в этом случае задача не запускается на исполнение при исполнении скипта самопроизвольно. Определение задачи какtask flaBuild(){ ... }
илиtask flaBuild{ ... }
запускает ее на исполнение вне зависимости от ее вызова. Скорее всего, это особенность groovy/gradle, которую я не знаю. - CS «держит» последний исполняемый jsfl или swc, поэтому задача
clean
не может удалить папку билда. Это можно поправить, добавив явное закрытие CS, но это сильно удлиннит сборку. Поэтому пока оставлю так.
Добавляю зависимость задачи build от задачи flaBuild и пробую получить доступ к ресурсу библиотеки, который экспортируется под именем «SymbolView». Прада, меня несколько смущает последовательность выполнения задач исходя из лога:
:copyresources
:compileFlex UP-TO-DATE
:flaBuild
:copytestresources
Это может означать, что я сделал зависимость не от той задачи. Точно, зависимость должна быть у задачи compileFlex, хоть ее и нет в общем списке задач gradle tasks
. Также должна быть зависимость от собранных fla-ресурсов. Я использовал возможность, которая есть в java плагине. Нашел ее случайно, посмотрев на список доступных свойст проекта. Возможно, это и не совсем честно, но раз уж подобное своейство есть, то почему бы и нет.
Итак, можно считать этап «fla, как статический ресурс», пройден.
Reliase compress
Для сжатия итоговой флехи буду использовать проект Apparat, с которым столкнулся, когда смотрел FlexMojos. Для maven есть стандарный плагин, который даже есть в репозитории. Я попробую воспользоваться частью для ant.
К сожалению, ant документации нет, но есть пример, его и возьму за основу. Неудача — для работы apparat требует scala. Устанавливать еще и ее, мне как-то не хочется. Возможно, позже. Было бы здорово здесь воспользоваться разрешением зависимостей, которую предоставляет maven-репозиторий, но это как бы не совсем зависимость проекта, это скорее аналог плагина. Другими словами я не очень понимаю как это потом использовать.
Нашел issue 47, так что это может быть реализовано более ровно. Поэтому пропускаю.
FlexPMD
Второй раз хочу использовать этот проект и второй раз это не удается сделать по простому. Фактическое отсутствие документации полностью отбивает охоту пробовать. В качестве репозитория наружу выставлен svn, кто хочет, может порыться. Часть его представляет из себя maven-репозиторий в очень своеобразном виде. Там лежат зипы, которые надо скачивать и распаковывать. Т.е. если я правильно понимаю, использовать это как maven зависимость не выйдет.
А вот неожиданно получилось, несмотря на своеобразность родной документации, удалось получить отчет по существующему коду. Правда, сделал только для одной директории исходников, но у меня больше и нет. К тому же исправить это совершенно не сложно.
Мне не очень понятно состояние этого проекта, он как бы нужный, но находится в очень запущенном виде, такое впечатление, что разработчиков взяли и одним днем перебросили на другие проекты. А этот ведется исключительно в свободное время. Хотя на бесплатное грешно батон крошить.
Много-модульный проект
В документации к плагину говорится, что многомодульные проекты делаются типово и отсылает к gradle документации. Ну, значит ее и буду пробовать. Разобью существующий проект на два: приложение и библиотека.
Все оказалось достаточно просто просто. Можно определять зависимости проектов между собой практически любым образом. Все проекты доступны друг для друга. Билд можно запускать как для любого проекта отдельно, так и для всех вместе.
Из неприятностей: проект стал собираться значительно дольше, порядка 21 секунды, против 14, как было раньше. Возможно, это решения для сервера интеграции.
В качестве заключения
Gralde очень мощный инструмент сборки, для типовых решений порог входа в него не велик. Для создания чего-то экзотического требуется знание groovy, gradle api и особенностей применяемых плагинов. Результирующий билд-скрипт в целом понятен, даже без знания groovy, гораздо компактней, чем xml.
GradleFX может практически все, что требуется для разработки. Мне не хватило только возможности автоустановки зипов, но это получилось сделать на коленке. Возможно это уже есть, поскольку существует зависимость типа archive, нужна возможность распаковки (или автоустановки). Не удалось попробовать разрешение сложных транзитивных зависимостей, но обещают, что это есть.
В целом, ощущения от пробы хорошие, гораздо лучше, чем от maven + FlexMojos. Хорошо, что стандарт есть, но нарушить его можно. Это особенно актуально для flex/flash, потому как здесь стандарты как-то не очень приживаются.
Поддержка со стороны IDEA заметно слабее, чем для maven. По факту доступны базовые функции вызова задач, поддержка написания самого скрипта отсутствует. Это странно, потому как groovy проекты делать можно и там это, скорее всего, есть.
Проект, на котором проводились эксперименты, там же есть черновик статьи, который писался по ходу действия. По дифам можно посмотреть, что именно и когда добавлялось.
Ресурсы
Gradle
Хабр о gradle
Maven -> Gradle примеры из жизни, обсуждение
GradleFX
jsfl
Apparat — framework to optmize ABC, SWC and SWF files
FlexPMD
Автор: nikolay_atamanyuk