1. Куча / Говнокод #17414

    +129

    1. 01
    2. 02
    3. 03
    4. 04
    5. 05
    6. 06
    7. 07
    8. 08
    9. 09
    10. 10
    11. 11
    12. 12
    13. 13
    14. 14
    15. 15
    16. 16
    17. 17
    18. 18
    19. 19
    20. 20
    21. 21
    22. 22
    23. 23
    24. 24
    25. 25
    26. 26
    27. 27
    28. 28
    29. 29
    30. 30
    31. 31
    32. 32
    33. 33
    34. 34
    35. 35
    36. 36
    37. 37
    38. 38
    39. 39
    40. 40
    41. 41
    42. 42
    43. 43
    44. 44
    45. 45
    46. 46
    47. 47
    48. 48
    49. 49
    50. 50
    51. 51
    52. 52
    53. 53
    54. 54
    55. 55
    56. 56
    57. 57
    58. 58
    59. 59
    60. 60
    <macrodef name="foreach">
      <attribute name="target"/>
      <attribute name="file-property"/>
      <element name="files"/>
      <element name="args"/>
      <sequential>
        <local name="foreach.files"/>
        <local name="foreach.target"/>
        <local name="foreach.file-property"/>
        <local name="foreach.args"/>
        <property name="foreach.target" value="@{target}"/>
        <property name="foreach.file-property" value="@{file-property}"/>
        <pathconvert property="foreach.files">
          <files/>
        </pathconvert>
        <propertyset id="foreach.args">
          <args/>
        </propertyset>
        <property name="foreach.args" refid="foreach.args"/>
        <property name="foreach.target" value="@{target}"/>
        <!-- there is no better way to do this at the moment
             property names and values should not contain comma-space and equals signs
        -->
        <script language="javascript"><![CDATA[
           var files = project.getProperty("foreach.files").split(":"),
           args = project.getProperty("foreach.args").split(", "),
           task = project.createTask("antcall"), arg;
    
           task.target = project.getProperty("foreach.target");
           for (var a in args) {
             arg = task.createParam();
             arg.setName(a.split("=")[0]);
             arg.setValue(String(a.split("=")[1]));
           }
    
           for (var f in files) {
             arg = task.createParam();
             arg.setName(project.getProperty("foreach.file-property"));
             arg.setValue(String(files[f]));
             task.perform();
           }
         ]]></script>
      </sequential>
    </macrodef>
    <!-- пример использования: -->
    
    <target name="transcode-font-helper">
      <property name="font.face.local" value="${font.face}"/>
      <foreach target="transcode-font" file-property="font.raw.source">
        <files>
          <fileset dir="${basedir}/fonts">
            <include name="*/${font.face.local}/*.otf"/>
            <include name="*/${font.face.local}/*.ttf"/>
          </fileset>
        </files>
        <args>
          <propertyref name="font.face.local"/>
        </args>
      </foreach>
    </target>

    А ведь если подумать: собрали все самое лучше, что есть в современном программировании - Ява, ХМЛ и ж.скрипт. Потом выбросили условные операторы, итерацию и операции со строкам - потому что не нужны. И получилась замечательная система для сборки проектов.

    Запостил: wvxvw, 06 Января 2015

    Комментарии (64) RSS

    • > И получилась замечательная система для сборки проектов.

      мы уже про это говорили здесь.

      потому что программисты думают только про программирование, и забывают про остальные фазы разработки (deployment, support). иногда даже про то что разница между release и debug может быть больше чем пара флагов компиляции.

      поэтому почти у всех модерновых билд систем база такая слабая. просто тупо скопировать пачку файлов из одного места в другое часто становится неподъёмной проблемой. зато для компиляции вообще ничего писать не надо!!! магия.
      Ответить
      • Я просто столько сил на этот форыч положил... и все равно лажа. Нужно еще как-то придумать как написать словарик, чтобы можно было произвольное количество пар ключ-значение передать. Пока на ум приходят только

        <keys><tokens><string>...</string></tokens></keys><values>...</values>


        Но это такая пытка это все расписывать. Плюс потом все равно очень легко ошибиться где чей ключ.
        Ответить
        • а что какой генератор прикрутить нельзя? т.е. что бы ant(?) читал не статический xml, а выхлоп какого препроцессора или просто скрипта?
          Ответить
          • Да на самом деле проблему можно было бы достаточно просто решить используя contrib библиотеки, или самому на той же Яве дописать пару классов. Проблема в том, что пользоваться этим не только мне, а еще четырем бойцам, у которых ушло чуть меньше полугода на то, чтобы подключить ант билд к Эклиспу... поэтому задача как можно меньше травмировать легкоранимую психику (даже после полугода бойцы как бы все еще не могут прийти в себя, и предпочитают антом собирать уже после того, как сделан коммит и отправлен на сервер билдов). Если немного усложнить процесс, то результатом будет то, что им просто перестанут пользоваться под любым предлогом.
            Ответить
        • и если список файлов не так часто меняется, то может быть можно просто полу-статически генерить кусок build.xml? и его вызывать из главного?
          Ответить
          • Этот форыч в нескольких местах используется. И это репозиторий с файлами шрифтов, которы нужно перекомпилировать из одного формата в другой, сгенерировать для некоторых превьюшки, поскладывать их по категориям и т.п. Т.е. файлы практически всегда будут разными (проект собирается только если файлов добавили или удалили).
            Ответить
    • что только не придумают люди, лишь бы не использовать gradle
      Ответить
      • Вот кстати да. При наличии граддла я могу толь микроцефалией объяснить использование анта
        Ответить
      • А объяснение, на самом деле очень простое. Адоб распространял в комплекте Флекс СДК описание Ант таска служащего интерфейсом к компилятору. Таск этот относительно легко заменяется макросом даже на том же Анте, но поскольку для того, чтобы это понять, нужно хоть немножко знать Ант, или другую похожую систему, то никто об этом не думал.

        На сегодняшний день использование адобовского таска составляет доли процента от всей сборки, но чем дальше, тем сложнее это все поменять.
        Ответить
        • http://www.gradle.org/docs/current/userguide/ant.html
          Ответить
          • Выглядит интересно, но как я уже говорил, тут у человека заняло неделю со спорами и упреками "установить" JDK (в Виндовсе все нужно устанавливать), просто для того, чтобы запустить билд. Поскольку контора небольшая, и специального devops человека в обозримом будущем не предвидиться, а брать на себя такие обязанности не хочется, мне бы лучше, чтобы остальные разработчики могли, хотя бы минимально обслуживать систему сборки.

            Не то, чтобы у них сейчас это хорошо получалось, но за полгода маленький прогресс все-таки есть. Переключиться на что-то другое: это мне обеспечит еще много ненависти и войны с ветряными мельницами...
            Ответить
            • У градла есть gradlew, который сам скачивает жарники, нужные для запуска градла, жарник бутстрапа принято коммитить прямо в репу. Т.е. в каком-то смысле градл устанавливать проще, чем ант (кроме того, gradlew скачивает конкретную версию).

              Сам не так давно переписал довольно большой билд с анта на градл, доволен как слон. Напрягает только небыстрый запуск сборки.

              Из плюсов - проекты для ИДЕ не нужно хранить в репе, нормальные ИДЕ могут генерить проекты прямо из gradle-файлов.

              Драться ни с кем не пришлось, благо, работаю с очень умными и приятными людьми.
              Ответить
            • > а брать на себя такие обязанности не хочется
              > это мне обеспечит еще много ненависти и войны с ветряными мельницами...

              обязанность != ответственность.

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

              другими словами, my way - or highway. только сформулировать надо помягче, что бы народ понял что не все на них висеть будет, но и ты какую-то часть ответственности перенимаешь.

              по моему опыту, если клиент тебя уже знает, то им даже и проще ответственность на кого-то другого свалить. да, козёл отпущения, но такова селяви.
              Ответить
              • Честно говоря, я вот взялся читать документацию, и пробовать что-то с этим сделать. Прямо скажем, никакого восторга. Опять какой-то умник пытается мне рассказать о том, что мен нужно, вместо того, чтобы сделать инструменты, которые мне нужны. Нельзя например, написать универсальный таск типа exec, который бы принимал параметры.
                Опять оказалось, что тривиальный скрипт на Питоне лучше и проще.
                Ответить
                • Аргументы, которые Градл передает шелл скрипту при интерполяции не экранируются, но и взять их в кавычки тоже нельзя. Очевидно, как и большинство Явы это писалось кнопконажимателями :/
                  Ответить
                  • сливать аргументы в файл можно? строка на аргумент. или даже 1 файл на 1 аргумент. знаю что капитальное говно, но пару раз на передаче параметров cygwin <-> mingw <-> windoz спасало.
                    Ответить
                    • Да ну, если таким заниматься, лучше уж написать на Питоне / Баше / и т.д. И потом, если очень хочется идти в ногу с модой вызвать из чего-то типа Грейдла :S
                      Ответить
                  • Непонятно только, зачем запускать шелл-скрипты из градла, если доступен полноценный язык программирования groovy вместе со всей жабьей библиотекой.
                    Ответить
                    • Вобщем, пока такое ощущение, что рожденный ползать летать не будет.

                      ant.importBuild "build.xml"
                      
                      task previewFonts << {
                        FileTree tree = fileTree(dir: "./fonts")
                        tree.include "**/*.otf"
                        tree.include "**/*.ttf"
                      
                        new File("./ant/previews").mkdirs()
                        
                        tree.each { f ->
                          def d = f.getParentFile()
                          if (d.getName() == "regular") {
                            d = d.getParentFile()
                      
                            def fname = f.getName().replaceFirst("[.][^.]+\$", "")
                          
                            Properties props = new Properties();
                            props.load(new FileInputStream(d.getPath() + "/description.properties"))
                      
                            def label = "label:" + new String(
                              props.getProperty("preview.text").getBytes("ISO-8859-1"), "UTF-8");
                            def fg = "label:" + props.getProperty("preview.foreground")
                            def bg = props.getProperty("preview.background")
                            def size = props.getProperty("preview.size")
                            def pname = new String(
                              props.getProperty("preview.name").getBytes("ISO-8859-1"), "UTF-8");
                            def png = "./ant/previews/${pname}.png"
                      
                            new ByteArrayOutputStream().withStream { es ->
                              def result = exec {
                                errorOutput = es
                                executable = "convert"
                                args "-background", bg, "-fill", fg, "-pointsize", size,
                                "-font", f, label, png
                              }
                              // TODO: Find out how to get the error message.
                              if (result.getExitValue() != 0) {
                                def message = new String("Preview not created: ${es.toString()}")
                                throw new GradleScriptException(message,
                                  new RuntimeException(message));
                              }
                            }
                          }
                        }
                      }

                      Судя по стек трейсам, все программы написаные на Яве до 2014 годе участвовали в запуске этого кода, но все равно, ни одна из них не взяла на себя труд бросить исключение, (да что там бросить исключение, просто скопировать сообщение об ошибке в строку!). И вы на полном серьезе считаете это достижением инжинерной мысли?
                      Ответить
                    • > зачем запускать шелл-скрипты из градла
                      Объясняется двумя словами: лень переписывать.
                      Ответить
                      • При чем тут лень? Мне нужен имиджмаджик, который, если я буду заменять Яваговном, займет непосильно много работы, будет дико тормозить и совершенно неподдерживаемый, по причине уникальности моего кода-оберктки.
                        Ответить
                        • Кстати, а вот этот экзек некорректно передаёт аргументы запускаемой проге?

                          http://www.gradle.org/docs/current/dsl/org.gradle.api.tasks.Exec.html
                          Ответить
                          • Это говно нельзя вызвать с параметрами. (с него я и начианал, собственно)

                            Этот аргументы передает корректно, некорректно - встроенный Груви тип строг ГСтринг (Г уже должно было насторожить в названии... но думал по-английски может прокатит). "ls ${someDirectory}".execute() - если в someDirectory будут пробелы, амперсанды и т.п. То мы получим шелл-иньекцию, или хз. как это назвать.
                            Ответить
                            • А так? ['ls', '/tmp/folder with spaces'].execute()

                              http://stackoverflow.com/questions/786160/groovy-execute-with-parameters-containing-spaces

                              P.S. Какое-то ебанутое использование ООП, имхо. Какого хуя список и строка умеют запускать проги?!
                              Ответить
                              • Надо будет завтра попробовать, дома лень это ставить.
                                Ответить
                              • Вобщем, шило на мыло. Ошибки он все равно не бросает (т.как возвращает java.lang.UNIXProcess), и сообщения об ошибке все равно парсить самому.
                                Ответить
                              • Лол, оно еще и валится с ошибками синхронизации, не смотря на то, что никто их даже не просил ничего выполнять параллельно... А кеширование сделано через такую жопу, что проще самому распарсить дифф, чем ебаться с этим говном. Потому что ввод/вывод для таска нельзя задать динамически, то для того, чтобы скомпилировать 50 файлов, мне нужно писать 50 тасков, или забить на кеширование.

                                Но что показательно, вот обычно читаешь документацию к библиотеке, и если людям хотелось попиарится, то могут туда бенчмарк вставить, или там цитату известного человека. Читаешь документацию Яваговна - что ни слово, то more powerful, more readable, more expressive и прочая ПР-хуйня вместо полезной информации.
                                Ответить
                                • Это поможет вам сохраненять инвестиции чтобы вы могли сохранять инвестиции сохраняя инвестиции.

                                  Из документации Cisco.
                                  Ответить
                                • > Потому что ввод/вывод для таска нельзя задать динамически
                                  Т.е. там нельзя делать свои сканеры зависимостей?

                                  Насчет динамического вывода трабла есть - если система не знает имя выходного файла заранее, то она тупо не сможет трекать зависимости. Или я туплю? Вроде бы все эти системы работают по принципу выход-старше-входа-надо-пересобрать?
                                  Ответить
                                • > мне нужно писать 50 тасков
                                  А что, если эти 50 тасков сгенерить циклом (как в http://govnokod.ru/17414#comment260826, только вместо exec запиливаем таски)? Тогда кеш должен заработать (но сканить каталог со входными файлами, походу, будет каждый раз, а как иначе, ведь они могли появиться/исчезнуть)...

                                  http://www.gradle.org/docs/current/userguide/tutorial_using_tasks.html#N1029F
                                  Ответить
                                  • > А что, если эти 50 тасков сгенерить циклом
                                    Ну в итоге я так и сделал. Жопа в том, что если мне такой же таск понадобится в другом месте для аналогичной задачи, то решение - только копипаста.
                                    В идеале (и СКонс это умеет), можно было бы научить таск, что если он применяется к каждому файлу в отдельности, а не ко всем вместе, то и при изменении нужно только применять к изменившимся.

                                    http://forums.gradle.org/gradle/topics/equivalent_for_ants_dirset
                                    Эти люди очевидно про работу с файлами слышали только по телевизору.
                                    Ответить
                                    • > то решение - только копипаста
                                      Я сейчас вот это читать начал, вроде бы как раз то что надо: The other type of task is the enhanced task, where the behaviour is built into the task, and the task provides some properties which you can use to configure the behaviour.

                                      https://gradle.org/docs/current/userguide/custom_tasks.html
                                      Ответить
                                    • > Эти люди очевидно про работу с файлами слышали только по телевизору.
                                      И про динамическое создание тасков, походу, тоже. Нету метода, генерящего уникальные айдишки для подобных тасков.
                                      Ответить
                                      • Оно кроме всего остального еще и пиздец какое ненадежное. Один и тот же билд файл даже с одной и той же версией Грейдла, с чистого листа один раз запускает одни таски, другой раз - нет. Нет никакой возможности сделать чистый билд, т.как оно само не в состоянии удалить свой кеш. Для таска копирования нельзя задать ввод/вывод. Нельзя получить вменяемый ответ на вопрос почему таск не был выполнен. Такое можно было написать либо от избытка мизантропии, либо от беспросветной тупости.
                                        Ответить
                                        • > с чистого листа один раз запускает одни таски, другой раз - нет
                                          Да там забавно... Если таск не кинул исключение - значит он выполнен. И похуй, что он описанные в outputs.files файлы не создал. Градл эту ситуацию всё равно закеширует. И больше этот таск никогда не запустится пока не изменится что-то в input'ах. После мейка непривычно, но логика в этом есть.

                                          > Нет никакой возможности сделать чистый билд
                                          Есть: --rerun-tasks заставляет его игнорить кеш. Ну или gradle clean сделай, если такой таск описан.
                                          Ответить
                                          • Ни --rerun-tasks ни -C rebuild не дают желаемый эффект. Хз где он хранит данные, но даже удаление папки .gradle не дает желаемого результата. doLast просто игнорируется. Т.е. в моем случае даже до попытки выполнения дело не доходит. Вренее, не всегда.
                                            Ответить
                    • Т.е. отвечая на вопрос: мне всего-то нужно было запустить imagemagic с пачкой файлов и сформировать имя результата и некоторые из опций из имени файла и списка свойств хранящихся в папке рядом с файлом. Баш / Питон уложился бы в 10-20 строчек (с комментариями), с нормальным сообщением об ошибках, аргументами коммандной строки и прочими удобствами.

                      А это хз... вобщем, я конечно еще попытаюсь дочитать маны и посмотреть на проекты побольше, но пока что цель этого мне не понятна. Это настолько несущественно улучшает Ант, что помоему нет смысла.
                      Ответить
                      • Граддл это гоуви. На груаи это тоже 3 строчки. Но зачем тебе это знать, правда? Зачем доки читать? Проще пойти на гк иляпнуть очередную чушь про джаваговно
                        Ответить
                        • Груви = Ява, только немножки с привкусом другого говна - Руби. Хз вообще такой язык мог кому-нибудь понадобиться.
                          Ответить
                          • I can honestly say if someone had shown me the Programming Scala book by by Martin Odersky, Lex Spoon & Bill Venners back in 2003 I'd probably have never created Groovy.
                            http://macstrac.blogspot.ru/2009/04/scala-as-long-term-replacement-for.html
                            Ответить
                            • Хз. Я когда смотрю на языки существующие для Ява рантайма, мне вспоминается анекдот про свечку и семью уродов. Назначение и смысл существования Скалы мне так же непонятен. Если бы я хотел писать на чем-то МЛ-подобном, то выбрал бы скорее всего ОКамл. Но я и не люблю такие языки вообще.

                              И вообще, у меня есть странное ощущение, что люди, которые занимаются изучением языков программирования и люди которые создают языки программирования - два непересекающихся множества. Даже без каких-то выдающихся познаний в теории или истории изучения языков программирования, читая авторов практически всех языков созданных в 21м* веке, сразу же обнаруживаются и фактические и теоретические несоответствия.

                              Или, другой вариант: Одерский как бы теоретик и у него все с этим вроде как хорошо, но это не помогает ему принимать хорошие решения - вместо того, чтобы руководствоваться принципом "сделать как лучше", чаще всего получается "сделать как нравится большинству".

                              * Раст, Меркури и еще несколько - приятные исключения.

                              По поводу статьи: снова powerful, concise и flexible, semantic и features - матерого Ява-програмиста видно издалека.
                              Ответить
                              • > Если бы я хотел писать на чем-то МЛ-подобном, то выбрал бы скорее всего ОКамл.

                                Дважды пытался выучить окамл, дважды забил. Намешали всего, получили месиво фич, паршиво друг с другом сочетающихся. Система типов страдает от мутабельности. Многопоточности нет.

                                Их приятного только система модулей и, возможно, camlp4.

                                Уж лучше скалка.

                                Если кто-то всё же решил выучить этот камл, советую Real World Ocaml, занятное чтиво.
                                Ответить
                                • Я хотел попробовать joCaml - это расширение с многопоточностью построенное на join calculus. Но руки так и не дошли.
                                  Если бы было время, то приоритеты были бы скорее всего такими: Shen, Mercury / Ciao, Loom, GP2, Rust. Но это не потому, что их где-то можно будет в обозримом будущем использовать, а потому, что интересно понять, как работает.
                                  Ответить
    • Теперь обезьяны будут говорить что хмл говно и тыкать этим кодом. Бгг
      Ответить
    • P.S. Пойду-ка just for fun напишу проект для gradle, который найдет и пережмет все серии указанных анимешек из сраного 10-битного x265 в 8-битный x264... С гредлом вообще не знаком, так что будет весело и познавательно.
      Ответить
      • Такие вещи, конечно, часто проще на make сделать.
        Gradle удобен там, где много жабоспецифики и есть иерархии жабопроектов.
        Только если ради fun...
        Ответить
        • Да я уже забил на эту идею :) Дефолтная проверка изменений в gradle слишком уж честная - он сверяет хеши входных и выходных(!) файлов. А они метров по 300-400. Тут разве что upToDateWhen() перекрыть, чтобы только даты сверял. Для таких вещей проще скриптик на питоне или баше набросать...

          Вот то, что успел наговнокодить: http://pastebin.com/KAhNF8eM

          P.S. Завтра попробую крестопроектик ради интереса портануть на gradle.
          Ответить
          • Если хочется поиграться, то есть ещё вот такая вундервафля от Фейсбука
            http://facebook.github.io/buck/
            Разумеется, тула специализированная, все типы тасков захардкожены, кастомные таргеты определять нельзя. Сомневаюсь, что эта штука получит широкое распространение, но дизайн у неё довольно интересный.
            Ответить
            • А зачем она, если есть граддл? Вообще фейсбук не может ничего путного сжелать
              Ответить
              • > А зачем она
                Чтобы сборка проекта шла менее нескольких минут.
                Градл юзабелен, но уж больно тормозной.

                > Вообще фейсбук не может ничего путного сжелать
                да ты я смотрю иксперт
                Ответить
                • > но уж больно тормозной
                  Это, походу из-за слишком честной проверки изменений?
                  Ответить
                  • У меня дольше всего идёт фаза чтения билд-файлов...
                    Ответить
                    • sources {
                          frontendServer {
                              cpp {
                                  source {
                                      srcDir "src"
                                      include "**/*.cpp"
                                  }
                                  exportedHeaders {
                                      srcDir "src"
                                      include "**/*.h"
                                  }
                              }
                          }
                      }
                      Меня вот тут exportedHeaders смущают. Без этого блока не пашет детектор зависимостей, и ничего не пересобирается если поправить ашку. А с ним все эти хедеры проникают во все зависимые проекты. Для экзешника, само собой, похер, а вот для либы неприятно... Неужели там нету никаких privateHeaders?
                      Ответить
          • Собрал градлом пару сишных проектов. Прикольно. Декларативненько.

            Только вот магия имён порой бесит. У меня экзешник назывался storage, ну я и назвал компонент так же, и смотрел как баран на ошибку "свойство storage не найдено"... Вбил как в примерах hello и main - работает. Пришлось назвать компонент storageServer.
            Ответить
          • Ради интереса решил проверить - как этот билд вообще что-то делает? Если я это запускаю, то все, что это делает:
            Skipping task ':repack' as it has no actions.
            :repack UP-TO-DATE
            Ответить
            • > has no actions
              Входных файлов не нашлось, скорее всего, поэтому репак ни одного таска не сгенерил, а в нём самом экшенов нету.
              Ответить
              • А, да, так и есть, ну почти, я маску неправильно задал. Еще тоже интересный момент. В принципе:
                FileTree fonts = fileTree(dir: "./fonts")
                fonts.include "**/regular/*.otf"
                fonts.include "**/regular/*.ttf"

                и
                FileTree fonts = fileTree(dir: "./fonts") {
                  include "**/regular/*.otf"
                  include "**/regular/*.ttf"
                }

                Должен делать одно и то же... ну как бы так ведь задумано, и вообще логично преположить по аналогии, да? Но вот делает он что-то непонятное вместо.
                Ответить
                • > Должен делать одно и то же
                  Ну в теории то да, вызывает include на объекте fonts. Но принимает ли fileTree вторым аргументом Closure?
                  Ответить
                  • А с такой документацией хер поймешь: http://www.gradle.org/docs/current/groovydoc/org/gradle/api/file/FileTree.html - я тут вообще конструкторов не вижу.

                    А ссылка на конкретную реалиазцию ведет вникуда. http://www.gradle.org/docs/current/groovydoc/org/gradle/api/Project.html#fileTree%28java.util.Map%29 . Т.е. нужно искать исходники и разбираться. Кстати об интерфейсах...
                    Ответить
                    • Вернее, вот даже, есть такой метод:
                      ConfigurableFileTree fileTree(Object baseDir, Closure configureClosure)

                      Так что можно было бы даже с большой долей уверенности предположить, что это должно работать - но тем не менее, хер.
                      Ответить
                      • // вот так не пашет
                        fileTree(dir: ".") {
                            include "**/*.java"
                        }
                        
                        // а вот так - все ок
                        fileTree(".") {
                            include "**/*.java"
                        }
                        Походу именованный параметр заставляет его выбрать другую перегрузку (ConfigurableFileTree fileTree(Map<String, ?> args)), которая юзает переданное замыкание через жопу (оно его даже вызывает).
                        Ответить
                        • Не, мне кажется, что выбирает правильную перегрузку, просто не догадывается, что имя диерктории находится в мапе.
                          Ответить
                          • Лол, да, сейчас потестил - он выбрал ту перегрузку. Но потом сделал мапу toString и пошел перечислять файлы в папке "{dir=.}", которой само-собой нету.
                            FileTree ft = fileTree(dir: ".") { }
                            println ft.dir
                            Ответить
    • Как и любой декларативный язык ant хорош тогда, когда у тебя файл сборки проекта занимает 9 строк.

      А как только он начинает занимать 150 -- так сразу надо что-то править в консерватории
      Ответить

    Добавить комментарий