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


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


Эта статья для тех, кто только начинает осваивать java.


image


В моей предыдущей статье было сказано, что maven сам скачает все указанные в pom.xml зависимости. А вот что будет, если он какую-нибудь зависимость не найдёт? В таком случае maven скажет, что зависимость не обнаружена и прервёт процесс сборки с ошибкой. Что делать в этом случае?


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


Зависимость может быть в интернете в каком-то месте, о существовании которого maven не знает. Ещё она может быть в виде jar файла у вас на руках и, наконец, в виде исходного кода, оформленного как maven проект.


Об этих трёх случаях мы и поговорим.


Но сначала надо коротко прояснить один вопрос.


Откуда maven качает библиотеки


На просторах интернета есть сервер, на котором выложены java библиотеки. Этот сервер называется репозиторием, а по-русски — хранилищем. Это не какой-то абстрактный, а вполне конкретный ресурс, адрес которого зашит в дефолтные настройки maven. Поэтому он называется репозиторием по умолчанию. Именно там maven будет искать зависимости из pom.xml.


Как быть, если библиотеки нет в удалённом хранилище по умолчанию, но она есть в другом удалённом хранилище


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


Причины проблемы немного разные, но решение одинаковое — нужно указать репозиторий, в котором зависимости есть. Это либо какой-то другой адрес в Интернете, либо адрес репозитория, поднятого админами в локальной сети.


Как указать maven проекту, где искать дополнительный репозиторий


Для того, чтобы указать maven, что зависимости надо искать не только в умолчальном репозитории, существует штатный механизм. Вот так можно прописать ещё один адрес для поиска.


<repositories>
    <repository>
      <id>id репозитория</id>
      <url>адрес репозитория</url>
    </repository>
 </repositories>

Далее мы подключили репозиторий проекта Spring, в котором можно найти последние версии этого семейства бибилиотек. Вот как это выглядит внутри pom.xml


<repository>
    <id>com.springsource.repository.bundles.release </id>
    <url>http://repository.springsource.com/maven/bundles/release </url>
</repository>

Теперь maven, когда не найдёт зависимости в репозитории по умолчанию, или обнаружит, что оный недоступен — не запаникует, а поищет библиотеку в ещё одном репозитории и, если всё идёт по плану, найдёт её там. Тут следует уточнить, что если ваша программа может быть использована в качестве зависимости, например, если сама является библиотекой, то класть тег репозиторий в pom.xml — не лучшая идея. Объяснение того, почему это так, выходит за рамки статьи, но с ним можно ознакомиться тут.


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


Как подключить библиотеку, которой в репозиториях нет


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


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


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


Как создать свой локальный репозиторий


Для этого, как сказано выше, у maven есть штатное средство.


Допустим у нас есть библиотека, которая находится в jar файле под названием hello-world-library-1.0-SNAPSHOT.jar. О библиотеке нам известно, что в ней есть один класс HelloWorld, который включает один статический метод say, печатающий в консоли, как несложно догадаться, Hello World.


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


mvn deploy:deploy-file -Durl=file:./lib -Dfile=hello-world-library-1.0-SNAPSHOT.jar -DgroupId=com.local -DartifactId=hello-world-library-local -Dpackaging=jar -Dversion=1.0-SNAPSHOT

Если вы используете операционную систему Windows, нужно заменить \ на ^, то есть написать


mvn ^
deploy:deploy-file ^
-Durl=file:./lib ^
-Dfile=hello-world-library-1.0-SNAPSHOT.jar ^
-DgroupId=com.local ^
-DartifactId=hello-world-library-local ^
-Dpackaging=jar ^
-Dversion=1.0-SNAPSHOT

Или можно просто убрать \ и написать команду в одну строчку.


mvn deploy:deploy-file -Durl=file:./lib -Dfile=hello-world-library-1.0-SNAPSHOT.jar -DgroupId=com.local -DartifactId=hello-world-library-local -Dpackaging=jar -Dversion=1.0-SNAPSHOT

Обратите внимание, как и для любого другого артефакта, для библиотеки нам нужно придумать groupId, artifactId и version. Мы потом укажем их в pom.xml, когда будем подключать зависимость.


Внутри директории, которую создаст команда, находится полноценный репозиторий, для использования которого достаточно указать maven, где он находится. Все сведения о том, какие библиотеки можно там найти, содержатся непосредственно в структуре директорий свежесозданного репозитория. Для последующего использования репозитория, например, на других машинах, команду deploy-file выполнять не надо.


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


<repositories>
    <repository>
        <id>localrep</id>
        <name>local repository</name>
        <url>file:${project.basedir}/lib</url>
    </repository>
</repositories>

Обратите внимание на пятую строку


<url>file:${project.basedir}/lib</url>

Тут сказано, что искать репозиторий надо в директории проекта, на которую указывает встроенная переменная maven project.basedir.


Класс, использующий библиотеку, будет предельно прост, но для порядка приведём его код.


package com;

import static com.HelloWorld.say;

public class Application {
    public static void main(String[] argv) {
        say();
    }
}

Осталось добавить в pom.xml зависимость и можно собирать проект.


<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">

    <modelVersion>4.0.0</modelVersion>
    <groupId>com</groupId>
    <artifactId>library-user-with-local-repository</artifactId>
    <version>1.0-SNAPSHOT</version>

    <repositories>
        <repository>
            <id>localrep</id>
            <name>local repository</name>
            <url>file:${project.basedir}/lib</url>
        </repository>
    </repositories>

    <dependencies>
        <dependency>
            <groupId>com.local</groupId>
            <artifactId>hello-world-library-local</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
    </dependencies>
</project>

Проверим:


mvn clean compile exec:java -Dexec.mainClass="com.Application"

Работает!


Директорию lib надо закомитить и библиотека будет доступна проекту вообще всегда.


Однако следует помнить об одном правиле.


Нужно обязательно обновлять номер версии библиотеки в локальном репозитории при каждом изменении jar файла


Maven воспринимает репозитории как внешние, поэтому, если не изменить номер версии, то maven будет использовать не версию библиотеки из директории lib, а ту, что он закешировал на локальной машине. В данном конкретном случае это не должно сыграть роли из-за суффикса SNAPSHOT, но об этом нужно знать.


Есть ещё один распространённый сценарий. У вас есть своя библиотека, которую вы сами собираете с помощью maven и потом подключаете к другому maven проекту.


Как сделать свою java библиотеку


Для того, чтобы сделать библиотеку, достаточно написать класс с модификатором public. И потом можно будет использовать этот класс в коде, к которому подключена библиотека.


Вот такой, например, класс.


package com;

public class HelloWorld {
    public static void say() {
        System.out.println("Hello world");
    }
}

Теперь нужно сделать maven проект, который будет собирать библиотеку, содержащую этот класс.


Как мы помним, с точки зрения maven, библиотека — это просто артефакт, поэтому помник будет выглядеть тривиально.


<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">

    <modelVersion>4.0.0</modelVersion>
    <groupId>com</groupId>
    <artifactId>hello-world-library</artifactId>
    <version>1.0-SNAPSHOT</version>
</project>

Итак, у нас есть класс со статическим методом, у нас есть описание артефакта для maven. Осталось только собрать этот код, чтобы получилась библиотека, то есть jar файл.


Просто напишем в консоли:


mvn package

После этого в директории target появится файл с названием \<artifactId>-\<version>.jar, в нашем конткретном случае — hello-world-library-1.0-SNAPSHOT.jar, который и есть ваша библиотека.


Как подключить свежесозданную библиотеку к своему maven проекту


Для того, чтобы библиотеку потом можно было подключать к другому проекту, нужно вместо package написать install.


mvn install

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


Теперь можно сделать новый проект, который будет использовать библиотеку.


<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">

    <modelVersion>4.0.0</modelVersion>
    <groupId>com</groupId>
    <artifactId>hello-world</artifactId>
    <version>1.0-SNAPSHOT</version>

    <dependencies>
        <dependency>
            <groupId>com</groupId>
            <artifactId>hello-world-library</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
    </dependencies>
</project>

Внутри проекта будет один класс, который использует статический метод из библиотеки, чтобы сказать Hello world. Мы этот класс уже видели.


package com;

import static com.HelloWorld.say;

public class Application {
    public static void main(String[] argv) {
        say();
    }
}

Проверим ещё раз:


mvn compile exec:java -Dexec.mainClass="com.Application"

Работает не хуже предыдущего варианта!


Что если ваша библиотека использует другую библиотеку?


Вопрос, казалось бы, глупый, но на всякий случай проведём эксперимент.


Сделаем библиотеку с непустыми зависимостями.


<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">

    <modelVersion>4.0.0</modelVersion>
    <groupId>com</groupId>
    <artifactId>hello-world-library</artifactId>
    <version>1.0-SNAPSHOT</version>

    <dependencies>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <version>3.4</version>
        </dependency>
    </dependencies>
</project>

и напишем для неё код


package com;

import static org.apache.commons.lang3.ArrayUtils.*;

public class HelloWorld {
    public static void say() {
        String[] phrase = {"Hello"};
        phrase = add(phrase, " ");
        phrase = add(phrase, "world");
        for (String word : phrase) {
            System.out.print(word);
        }
        System.out.println();
    }
}

Теперь соберём её


mvn clean install

Перейдём в директорию с нашим проектом, который эту библиотеку использует и попробуем его собрать и запустить.


mvn clean compile exec:java -Dexec.mainClass="com.Application"

И работает!


Как это работает


Строго говоря знать, как процесс устроен внутри, не обязательно, но всё равно очень полезно.


Команда mvn install соберёт библиотеку, а потом положит её в локальный репозиторий по умолчанию. То есть в то же самое место, где лежат все библиотеки, которые вы когда-либо подключали к maven проектам, за исключением, разумеется, тех, которые находятся в локальных репозиториях, сделанных лично вами.


Потом, при сборке проекта, использующего эту библиотеку, maven поищет её в локальном хранилище, найдёт и подключит.


Итого


  • Maven ищет библиотеки в удалённом репозитории по умолчанию.
  • Чтобы подключить библиотеку, которой нет в репозитории по умолчанию, можно указать дополнительные удалённые репозитории, тогда maven будет искать библиотеки ещё и в них.
  • Если библиотеки нет ни в одном удалённом репозитории, то можно с помощью штатного механизма maven создать локальный репозиторий и добавить его в pom.xml.
  • При обновлении репозитория, который находится в исходниках проекта, нужно всегда менять версию библиотеки, иначе могут быть непонятные проблемы.
  • Если у вас есть maven проект, то из него можно сделать библиотеку командой mvn package.
  • Командой mvn install можно поместить библиотеку в локальный репозиторий по умолчанию.
  • Чтобы использовать библиотеку в другом проекте, достаточно указать её в качестве зависимости в pom.xml.

UPD: В комментариях sshikov, igor_suhorukov, jbaruch и другие высказали мнение, что библиотеки нельзя хранить вместе с исходниками, потому что для этого есть другие, предназначенные специально для этого инструменты, такие как Nexus и Artifactory.


Тут я совершенно согласен. Когда речь идёт о крупных проектах и корпоративной разработке, быть по-другому просто не может. Но, с моей точки зрения, есть случаи, когда удобнее сделать иначе. Я имею в виду маленькие проекты, созданные в процессе обучения, потому что именно с такими вещами обычно имеют дело новички, и случаи, когда доступа к инфраструктуре нет, а добавить библиотеку в сборку нужно в течение 10 минут. Нужно было с самого начала уточнить, что речь в статье именно о таких кейсах.


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


Причины, по которым техника, предложенная в статье, не подходит для корпоративной разработки, хорошо раскрыты в комментариях. Также советую обратить внимание на статью от разработчиков Nexus, спасибо jbaruch за ссылку. Статья интересная, если не найду существующего перевода на Хабре, планирую перевести ее и сделать отдельным постом.

Поделиться с друзьями
-->

Комментарии (55)


  1. sshikov
    02.03.2017 13:31
    +9

    Ну вот зачем вы учите начинающих плохому? )))

    Есть менеджеры репозиториев, например nexus и artifactory. У них есть полноценные бесплатные версии, которые (конкретно могу утверждать про nexus, но не думаю что с другими все сильно отличается) устанавливаются и запускаются максимум за полчаса. Есть например готовые docker images, откуда можно запустить вообще без усилий, если у вас есть docker.

    И дальше свой nexus надо прописать раз и навсегда в settings.xml, и с ним работать. Если вы не кустарь одиночка с мотором (с), это будет одно из правильных решений. А если вы работаете в команде — то пожалуй и единственно правильное.

    Установить и запустить. И дальше все проблемы будут решаться через UI — задеплоить артефакт, которого нет в репозиториях, подключить еще один репозиторий помимо central, и прочее, и прочее.


    1. poxvuibr
      02.03.2017 14:01
      -1

      Ну вот зачем вы учите начинающих плохому? )))
      Есть менеджеры репозиториев, например nexus и artifactory.

      Я тут совершенно согласен часто нужно класть библиотеки именно туда. В статье об этом есть ремарка :)


      И дальше свой nexus надо прописать раз и навсегда в settings.xml, и с ним работать.

      А вот тут я считаю, что настройки надо по возможности воткнуть в pom.xml и завернуть в maven профиль, чтобы не было необходимости что-то настраивать в settings.xml


      Если вы не кустарь одиночка с мотором (с), это будет одно из правильных решений. А если вы работаете в команде — то пожалуй и единственно правильное.

      А если вы в команде — тем более класть в профиль, чтобы не заниматься правкой settings.xml на регулярной основе


      Установить и запустить. И дальше все проблемы будут решаться через UI — задеплоить артефакт, которого нет в репозиториях, подключить еще один репозиторий помимо central, и прочее, и прочее.

      Это, повторюсь, хороший вариант. В статье я хотел сделать фокус именно на работе с maven. Этот вариант работы, на мой взгляд, описан в пункте про подключение удалённого репозитория.


      1. sshikov
        02.03.2017 14:27
        +2

        Да, с поправками насчет settings и пр. — согласен.

        Собственно, я имел в виду, что ваши варианты — они конечно да, самые базовые, но в реальности все-таки намного проще настроить репозиторий. В случае компании, которая живет в интранете — это просто must have, без вариантов вообще. И на это стоило бы напирать сильнее.


    1. Throwable
      02.03.2017 14:14
      +2

      Я не совсем согласен с такой точкой зрения. Иметь свой корпоративный репозиторий в команде это, конечно же, хорошо и правильно. Но я всегда следую принципу, что проект должен уметь собираться всегда и везде, без лишних геморроев. Локальный репозиторий проекта — разумное решение, когда тебе нужен всего лишь какой-нибудь пропиетарный драйвер. Это делает сборку проекта автономной и независимой от окружения. Maven Wrapper при этом еще отлично помогает.


      1. sshikov
        02.03.2017 14:32

        Ну да. Наверное все-таки стоит разделить проекты на open source (которым в первую очередь нужно собираться везде), и скажем так, корпоративные.

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


      1. poxvuibr
        02.03.2017 14:32
        +1

        Это делает сборку проекта автономной и независимой от окружения. Maven Wrapper при этом еще отлично помогает.

        Именно это я и имел в виду. А Maven Wrapper — вещь! Я когда gradlew увидел — долго горевал, что для maven такого нет. Пока через час не выяснил, что вполне себе есть!


    1. jbaruch
      03.03.2017 19:32
      +4

      Спасибо, дорогой за луч света в этом плотном слое говна. Я тут обфейспалмился до крови, читая этот ад (я про статью, конечно). У Artifactory тоже есть бесплатный оpensource, конечно. У нас есть генератор settings.xml, который вообще делает всё за тебя: https://www.youtube.com/watch?v=MGXrPz9wwOY


      Кроме того, у нас есть еще и Maven plugin, который добавляет metadata к задеплоенным артифактам.


  1. vaniaPooh
    02.03.2017 13:44

    mvn deploy:deploy-file

    А потом вы ошибаетесь в -Dpackaging=pom и записываете вместо pom — jar. Поздравляю — у вас битый локальный репозиторий и теперь резолв артефакта будет идти с ошибкой.


    1. poxvuibr
      02.03.2017 14:18
      -3

      Это же попадёт в систему контроля версий. Можно будет по коммиту найти виноватых, наказать невиновных и наградить непричастных :)


      1. vaniaPooh
        03.03.2017 17:27
        +1

        Не попадет. Если только вы не храните локальный репозиторий под версионным контролем.


        1. jbaruch
          03.03.2017 19:50
          +4

          Хранят, хранят. Это то, что они предлагают в статье.


  1. Throwable
    02.03.2017 13:59

    Есть одна проблема с локальным репозиторием — для мультимодульного проекта придется корректировать путь к нему в каждом pom.xml, так как project.badedir будет у каждого модуля свой.


    1. poxvuibr
      02.03.2017 14:09
      -1

      Есть одна проблема с локальным репозиторием — для мультимодульного проекта придется корректировать путь к нему в каждом pom.xml, так как project.badedir будет у каждого модуля свой.

      Есть, да. Многомодульному проекту в maven вообще хочется посвятить отдельную публикацию — очень уж актуальная и важная тема.


  1. sbnur
    02.03.2017 15:01

    К слову, maven уже 15 лет и означает собиратель знаний
    Это к тому, что уже давно все собрано в смысле знаний о самом maven и его использовании


    1. vba
      02.03.2017 15:40
      +1

      Да 15 лет и такое впечатление что он нисколько не изменился за эти 15 лет, да и просто не может меняться.


    1. poxvuibr
      02.03.2017 15:44
      +1

      Ньютоновской физике даже больше 15, а учебники всё пишут и пишут :). Я попытался написать статью именно такой, какой хотел видеть её, когда про maven ещё ничего не знал. Написал с надеждой, что найдутся люди, которым будет удобно получить знания именно в такой форме.


      1. AstarothAst
        02.03.2017 16:48
        +2

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


  1. jehy
    02.03.2017 18:46
    -3

    А гораздо проще сделать это так:

    maven { url 'https://jitpack.io' }

    dependencies {
    compile 'com.github.jehy:Tor-Onion-Proxy-Library:0.0.5'
    }


    И вот у вас прямо из гитхаба идёт импорт.


    1. poxvuibr
      02.03.2017 19:29
      +1

      Во-первых это не совсем maven :). А во-вторых импорты с гитхаба штука опасная, если он конечно не твой собственный.


      1. jehy
        02.03.2017 19:36
        -1

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


        1. poxvuibr
          03.03.2017 09:12
          +1

          Ну, тема статьи всё-таки maven. Поэтому на всякий случай перепишу ваше замечание так, чтобы оно лучше соответствовало контексту статьи.


          <repository>
              <id>jitpack.io</id>
              <url>https://jitpack.io</url>
          </repository>
          
          <dependency>
              <groupId>com.github.jehy</groupId>
              <artifactId>Tor-Onion-Proxy-Library</artifactId>
              <version>0.0.5</version>
          </dependency>

          Действительно неплохой способ. Собирать библиотеки только нужно, но для многих это скорее плюс, чем минус. Жаль только завязан на проприетарную технологию с закрытым кодом. А так — вполне себе.


          1. jbaruch
            03.03.2017 19:53

            прописывать repository в поме — огромная ошибка. Никогда так не делайте, и никого не учите так делать. Вот вам блог пост от создателей мавена:
            http://blog.sonatype.com/2009/02/why-putting-repositories-in-your-poms-is-a-bad-idea/


            1. poxvuibr
              06.03.2017 13:11

              repository в pom.xml это действительно не всегда хорошо. Однако, в приведённой вами статье написано, что в случае, если продуктом является программа, которую не собираются использовать в качестве зависимости, то указание репозитория в помнике вполне безопасно. И, если вы хотите упростить сборку проекта для других разработчиков эта идея вполне заслуживает рассмотрения. Именно о таких кейсах я говорил. Спасибо за замечание, добавил уточнение в статье.


              1. grossws
                06.03.2017 13:13

                Особенно весело видеть в конечном приложении такой repository, который требует аутентификации ,)


                1. jbaruch
                  06.03.2017 13:46

                  А то, конечно, требует.


              1. jbaruch
                06.03.2017 13:45

                В приведенной мной статье, персонажи, которые придумали этот ад изначально, пытаются оправдаться в стиле «да, это конечно ужас, но не ужас-ужас». Repository в pom это bad practice, и точка. Settings.xml всё равно надо будет генерить для каждого разработчика (потому что там их личные credentials), поэтому нет никаких проблем держать там репозитории тоже.


          1. jehy
            04.03.2017 11:01

            А, вы про то, что это Gradle. Да, моя ошибка. Думал, будет всем понятно и так…


  1. igor_suhorukov
    02.03.2017 23:44
    +3

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

    А вот так делать не надо!!! Есть грань между SCM и binary repository manager которую не следует путать. Свой собственный корпоративный репозитарий — правильное решение. Хранение библиотек в SCM — грязный хак!


    1. poxvuibr
      03.03.2017 08:17

      А вот так делать не надо!!! Есть грань между SCM и binary repository manager которую не следует путать.

      Вопрос в том, где эта грань. Тут как с картинками и всем таким. Если у вас их пара гигабайт, то нужно хранить отдельно. Хотя всякое бывает :). А, если пара иконок, то обычно хранят прямо в системе контроля версий. С библиотеками похожая ситуация. Если есть один проприетарный драйвер, или небольшой джарник из эпохи мамонтов с утерянными исходниками — то можно и прямо в исходники положить. А если там целая система с зависимостями, то лучше как-то по другому делать.


      Свой собственный корпоративный репозитарий — правильное решение.

      Особенно, если у вас есть своя собственная корпорация :). А если у вас свой проектик с парой джарников, то корпоративный репозиторий возможно и оверкилл.


      Хранение библиотек в SCM — грязный хак!

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


      1. sshikov
        03.03.2017 09:28
        +1

        Свой репозиторий оверкилл только если результат проекта вам почти совсем не важен. А если важен — то репозиторий все равно понадобится. В идеале — положить в central. И потом — это в конечном счете быстрее, иметь свой кеш внутри команды.

        А про хранение внутри SCM — я бы сказал так: хранить можно, но желательно даже в этом случае разделить репозитории. Пусть у вас будет git repo — но отдельный и только для артефактов. У них другой жизненный цикл, чем у ваших исходников, вы не будете делать такие же бранчи, релизить, и прочее и прочеее. А значит — разделить.


      1. igor_suhorukov
        03.03.2017 10:06
        +1

        А если у вас свой проектик с парой джарников, то корпоративный репозиторий возможно и оверкилл.

        Для проектов с открытым исходным кодом можно использовать центральный репозитарий. Тогда ваши артефакты могут указывать в зависимостях без подкладываний jar в SCM или deploy в корпоративный репозитарий. Есть nexus opensource edition и установка простая — скачал и запустил. Если же проект не open source и вам лень ставить свой менеджер репозитариев и делать бэкапы, то можете раскошелиться на подписку bintray и использовать как сервис для не общедоступного репозитария.

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

        По мне так ответ проще — для хранения jpg/png для веб приложений, которых огромное число в github.


        1. poxvuibr
          03.03.2017 10:20

          Если же проект не open source и вам лень ставить свой менеджер репозитариев и делать бэкапы, то можете раскошелиться на подписку bintray и использовать как сервис для не общедоступного репозитария.

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


          1. igor_suhorukov
            03.03.2017 19:12

            Странно что jbaruch промолчал про bintray и эту ситуацию со складированием библиотек в SCM…


            1. jbaruch
              03.03.2017 19:17
              +3

              Да я тут уже обфейспалмился до крови.


              1. jbaruch
                03.03.2017 19:27

                И кстати, Артифактори подходит гораздо больше, и он бесплатен.


            1. sshikov
              03.03.2017 19:54

              А что не так с bintray? Это же и есть репозиторий, в общем-то.

              Что же до SCM — то есть помнится возможность деплоить туда артефакты при помощи штатного механизма — т.е. mvn deploy. При этом SCM у вас играет роль хранилища, но работаете вы с ним как с репозиторием.

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

              У меня вот в проекте (предыдущем на сегодня) был (и есть) nexus. Тому нексусу — наверное лет 6 или 10 уже. Никого из тех, кто его развертывал, уже давно в компании нет. Рядом, если что, такой же дремучий jenkins. Никто их не поддерживает — разве что время от времени чистят диск от ненужных сборок jenkins. И работают с этим добром человек 20. Вот такие они — трудозатраты, по стоимости машинки для запуска (виртуалка на два ядра и 8Гб) и диска для размещения всего добра, гигабайт на 100.


              1. jbaruch
                03.03.2017 21:43

                С бинтреем всё так, но он просто не для разработки, а для дистрибуции. Для разработки больше Артифактори подходит. Мы в Разборе Полётов всё таки когда нибудь доберемся до разницы между ними (но не в следущем выпуске точно).


          1. sshikov
            03.03.2017 22:12
            +1

            Тут понимаете еще какая штука… Сначала пара jar, потом десять. А потом будет как в одном моем старом проекте — огромная папка lib, одна на 50 проектов, и порядка 50-же разработчиков.

            И валяется там на 99% вполне себе open source, типа commons collections, и огромная проблема со всем этим состоит в том, что никто уже не знает, какому проекту на самом деле какие завимости нужны, кто от кого зависит, какие у них версии, и прочая и прочая.

            Там правда к этому еще прилагался ant, но разница в общем не очень велика, потому что главная проблема не в том, чем собирать, а в том, что где-то в lib лежит нечто, о чем мы не знаем, как его точно зовут, и какой оно версии. И если завтра кто-то заменит в SCM один jar на другой, похожий — мы долго будем думать, почему оно вдруг сломалось.


        1. jbaruch
          03.03.2017 19:40
          +1

          Bintray такой же бесплатный для opensource, а jcenter такой же центральный как и central, и Artifactory такой же бесплатный и опенсорцный как Нексус (только у нас генератор settings.xml и/или maven plugin еще есть).
          https://www.youtube.com/watch?v=MGXrPz9wwOY
          https://www.jfrog.com/confluence/display/RTF/Maven+Artifactory+Plugin


          1. grossws
            03.03.2017 21:35

            Всё-таки central — репозиторий по умолчанию для maven'а, а jcenter надо явно прописывать в settings.xml или добавлять в группу в nexus/artifactory. С остальным сложно не согласиться ,)


            1. jbaruch
              03.03.2017 21:42

              Да, но с генераторами сеттингов и в Бинтрее и в Артифактори это достаточно просто.


  1. moryakov
    03.03.2017 08:06
    +2

    Из инструментария я отметил бы еще Apache Archiva


  1. jbaruch
    03.03.2017 19:21
    +4

    Что же вы делаете-то?! Tutorial в корпоративном блоге предлагает "Директорию lib надо закомитить и библиотека будет доступна проекту вообще всегда"? Я думаю следущая статья должна быть о том, как сорцы лучше пересылать по email-у.


    1. grossws
      03.03.2017 21:31
      +3

      К сожалению, эта тенденция в большинстве корпоративных блогов на хабре. Есть исключения (в особенности среди больших корпоратов типа mailru/yandex/ibm), но большинство тупо получает деньги за количество знаков, а не качество, вот и прёт индусятина в новом обличье.


      1. jbaruch
        03.03.2017 21:41

        Вот индусам сейчас обидно было.


        1. grossws
          03.03.2017 21:44
          +1

          Не все индусы одинаково полезны. Я знаю некоторое количество тех, кто реально неплохой код пишет и поддерживает. Но иногда с ужасом вспоминаю исходники какого-нибудь Atlassian Crowd'а.


          1. jbaruch
            03.03.2017 21:52

            Как и не все русские, и не все американцы, я бы сказал. Особенно в свете обсуждения качества статей на Хабре.


            1. grossws
              03.03.2017 22:06
              +1

              Стереотип не на пустом месте появился, и отсылка была именно к нему, а не к национальности.


              Проблема-то та же самая, многим копирайтерам платят за объём и частоту публикаций, а не за качество, так что результат немного предсказуем.


  1. grossws
    03.03.2017 21:42

    @jbaruch, раз уж вы здесь, поведайте как у artifactory (open-source варианта) обстоят дела по следующим направлениям:


    • внешняя authn/authz через http-заголовок (типа REMOTE_USER) или openid connect;
    • как с возможностью автоматического деплоя в него из jenkins (при использовании jenkinsfile/pipeline plugin);
    • как с возможностью использования webhook'ов/rest api для уведомлений о деплое артифакта?

    В принципе, artifactory мне на первый взгляд приятней, чем nexus (а в третьей версии он таки местами ужасен), но когда смотрел в прошлый раз, отсутствие некоторых фич было блокером для сборки CI/CD pipeline'а на open-source варианте.


    1. jbaruch
      03.03.2017 21:46
      +1

      • В бесплатном есть только LDAP
      • Это конечно всё есть, и через Artifactory Jenkins Plugin, и через Artifactory Maven Plugin (оба open source) и просто через mvn deploy
      • Это через user plugin, который в Pro.


      1. grossws
        03.03.2017 22:03

        Понятно, спасибо. Т. е. в теории вполне реально, если всё делать со стороны jenkins'а. Надо пробовать.


        В планах sso/oidc отдать в opensource нет? То у меня есть впечатление, что раньше ldap был только в pro. И аналогичный вопрос про docker-репозитории.


        1. jbaruch
          04.03.2017 10:24

          ldap всегда был в open-source. Планов переносить что-то из pro пока нет.


    1. sshikov
      03.03.2017 22:27

      Пардон, мне кажется, или вы хотите странного?

      1. Вы когда деплоите, вы скорее всего используете http, и один из стандартных механизмов аутентификации юзера. Basic, NTLM, SSL. Чтобы использовать тут внешнюю, нужно допилить maven deploy plugin, а точнее видимо вагон. Внешняя тут зачем, чтобы использовать ее в этом месте вместо LDAP? Тогда это Artifactory Security Realm (ровно также, как у nexus впрочем). Это не очень сложно, я пробовал.
      2. Проще всего mvn deploy, разумеется. Остальное дополнительные плюшки.
      3. В nexus для этого есть RSS и расылка нотификаций почтой. Как вы хотите получать уведомления, если это асинхронный процесс? Чей это должен быть REST? Jenkins, чтобы он собрал другой зависимый артефакт?


      1. grossws
        03.03.2017 22:50

        Не то чтобы очень странного ,)


        1. Я не против использования http authn для деплоя (из jenkins'а или из maven/gradle/sbt — не важно), но для работы с самим artifactory/nexus хочется иметь поменьше геморроя, в частности SSO. OIDC в этом плане является стандартом наравне с более сложным и неприятным SAML, который мне сильно избыточен. И сервер авторизации, поддерживающий OIDC (Keycloak в моём случае) может поддерживать, например, 2fa/client tls auth и подобные радости.
        2. про mvn deploy всё более-менее понятно. Он мне местами не очень нравится (в частности, необходимостью дублировать scm и иметь distributionManagement в parent'е). Причем, иногда хочется из jenkins'а подтвердить promotion в stage окружение, а далее в release. С jenkins pipeline это вполне реализуемо. Но пока у меня нет устоявшегося представление как это всё будет выглядеть, так что я присматриваюсь к разным вариантам.
        3. В свой сервис обычным http callback'ом (т. е. то, что обычно и понимается под webhook'ом), а он уже может выполнять задачи по уведомлению, используя какой-нибудь slack и т. п. Вполне возможно, что всё может делаться из jenkins'а и придумал себе проблему на пустом месте.