Ввод паролей при сборке проектов с помощью gradle

от автора

При сборке проектов для Android Gradle позволяет указать некоторые параметры, позволяющие собрать и подписать пакет, готовый для загрузки в Google Play. Однако, вряд ли стоит загружать некоторые данные, такие как пароль от приватного ключа в публичный репозиторий. В статье, перевод которой ниже, автор рассматривает способы ввода приватной информации, такой как пароли, во время сборки проекта.

Gradle позволяет получить доступ к консоли с помощью метода System.console(). Консоль предоставляет метод для чтения паролей, поэтому для ввода пароля можно использовать:

def password = System.console().readPassword("\nPlease enter key passphrase: ") 

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

Проблема №1 — не нужно донимать меня постоянно.

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

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

gradle.taskGraph.whenReady { taskGraph ->   // Выполняется, когда TaskGraph готов. } 

Просто разместите этот кусок кода в скрипт сборки и код внутри него будет выполнен, когда граф будет готов.

Теперь необходимо проверить, что мы выполняем задачу, которая нуждается в вводе пароля. В TaskGraph имеется метод hasTask(), предназначенный лдя того, что определенная задача будет исполняться во время сборки. Необходимо указать имя задачи в качестве параметра. Также, вы должны указать двоеточие перед именем корневого каталога. Если задача определена в каком-то подмодуле (как это обычно бывает в android-проектах), вы также должны указать имя этого модуля. Пусть в вашем проекте есть модуль app и нам нужен пароль от ключа, когда мы выполняем assembleRelease. Так мы можем сделать необходимую проверку:

gradle.taskGraph.whenReady { taskGraph ->   if(taskGraph.hasTask(':app:assembleRelease')) {     //Выполняется только тогда, когда мы делаем релизную сборку      def pass = System.console().readPassword("\nPlease enter key passphrase: ")     // readPassword возвращает  char[], поэтому нам нужно обернуть результат в String      pass = new String(pass)     // А здесь можно использовать переменную pass    } } 

Теперь gradle не будет вас беспокоить, пока ему не понадобится пароль.

Проблема №2 — У нас нет консоли.

Если вы попробуете выполнить код, приведённый выше в IDE (например, в Android Studio) или с помощью gradle.daemon, у вас не будет доступа к консоли (System.console() вернёт null) и сборка сломается из-за исключения. Но не стоит паниковать, эта проблема решаема. Если у нас нет доступа к консоли, у нас все еще есть UI. Мы можем использовать SwngBuilder из Groovy, чтобы показать простой диалог ввода пароля.

Во-первых, необходимо его импортировать, так что разместите следующую строку в начале вашего build.gradle:

import groovy.swing.SwingBuilder 

Теперь вы можете использовать SwingBuilder, чтобы показать простой диалог ввода:

def pass = '' new SwingBuilder().edt {   dialog(modal: true, //иначе сборка продолжится до того, как вы закроете диалог.       title: 'Enter password',       alwaysOnTop: true,       resizable: false,       locationRelativeTo: null, // Расположить диалог в центре экрана.       pack: true,       show: true   ) {     vbox {       label(text: "Please enter key passphrase:")       input = passwordField()       button(defaultButton: true, text: 'OK', actionPerformed: {         pass = input.password;         dispose();        })     }   } } 

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

Соединяем всё вместе.

Давайте теперь соберём все это вместе. UI хорош (ок, тот, который мы использовали ранее не очень хорош, но вы свободны модифицировать его как хотите: SwingBuilder docs), но возможно иногда вам нужно будет собирать на системе, где есть только консоль и нет графического интерфейса (как сервер сборки) и иногда из вашей IDE. Также возможно, вы хотели бы отменить сборку, если пользователь не ввёл пароль. Теперь ваш скрипт сборки должен выглядеть так:

gradle.taskGraph.whenReady { taskGraph ->   if(taskGraph.hasTask(':app:assembleRelease')) {     def pass = ''     if(System.console() == null) {       new SwingBuilder().edt {         dialog(modal: true,             title: 'Enter password',             alwaysOnTop: true,             resizable: false,             locationRelativeTo: null,             pack: true,             show: true         ) {           vbox {              label(text: "Please enter key passphrase:")             input = passwordField()             button(defaultButton: true, text: 'OK', actionPerformed: {               pass = input.password               dispose();             })           }         }       }     } else {       pass = System.console().readPassword("\nPlease enter key passphrase: ")       pass = new String(pass)     }       if(pass.size() <= 0) {       throw new InvalidUserDataException("You must enter a password to proceed.")     }       // -----     // Здесь можно делать с переменной pass все, что нужно!     // -----     } }  

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

ссылка на оригинал статьи http://habrahabr.ru/post/221741/


Комментарии

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

Ваш адрес email не будет опубликован. Обязательные поля помечены *