Gradle use-python plugin
About
Plugin does not install python and pip itself and use globally installed python (by default). It's easier to prepare python manually because python have good compatibility (from user perspective) and does not need to be updated often.
The only plugin intention is to simplify python usage from gradle. By default, plugin creates python virtualenv inside the project and installs all modules there so each project has its own python (copy) and could not be affected by other projects or system changes.
Features:
- Install required python modules using pip (per project (virtualenv), os user (--user) or globally)
- Provides task to call python commands, modules or scripts (
PythonTask
) - Could be used as basement for building plugins for specific python modules (like mkdocs plugin)
Summary
- Configuration:
python
- Tasks:
checkPython
- validate python installation (and create virtualenv if required)pipInstall
- install declared pip modulespipUpdates
- show the latest available versions for the registered modulespipList
- show all installed modules (the same as pipInstall shows after installation)type:PythonTask
- call python command/script/moduletype:PipInstallTask
- may be used for custom pip modules installation workflow
Possible pip issue warning (linux/macos)
If pip3 list -o
fails with: TypeError: '>' not supported between instances of 'Version' and 'Version'
Then simply update installed pip version: python3 -m pip install --upgrade pip
This is a known issue related to incorrectly patched pip packages in some distributions.
Setup
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'ru.vyarus:gradle-use-python-plugin:2.3.0'
}
}
apply plugin: 'ru.vyarus.use-python'
OR
plugins {
id 'ru.vyarus.use-python' version '2.3.0'
}
Compatibility
Plugin compiled for java 8, compatible with java 11
Gradle | Version |
---|---|
5-6 | 2.3.0 |
4.x | 1.2.0 |
Snapshots
Snapshots may be used through JitPack
- Go to JitPack project page
- Select
Commits
section and clickGet it
on commit you want to use or usemaster-SNAPSHOT
to use the most recent snapshot
For gradle before 6.0 use buildscript
block with required commit hash as version:
buildscript {
repositories {
maven { url 'https://jitpack.io' }
}
dependencies {
classpath 'ru.vyarus:gradle-use-python-plugin:2450c7e881'
}
}
apply plugin: 'ru.vyarus.use-python'
For gradle 6.0 and above:
-
Add to
settings.gradle
(top most!) with required commit hash as version:pluginManagement { resolutionStrategy { eachPlugin { if (requested.id.namespace == 'ru.vyarus.use-python') { useModule('ru.vyarus:gradle-use-python-plugin:2450c7e881') } } } repositories { maven { url 'https://jitpack.io' } gradlePluginPortal() } }
-
Use plugin without declaring version:
plugins { id 'ru.vyarus.use-python' }
Python & Pip
Make sure python and pip are installed:
python --version
pip --version
On *nix python
usually reference python2. For python3:
python3 --version
pip3 --version
Windows install
Download and install python manually or use chocolately:
choco install python
In Windows 10 python 3.9 could be installed from Windows Store: just type 'python' in console and windows will open Windows Store's python page. No additional actions required after installation.
Note that windows store python will require minium virtualenv 20.0.11 (or above). (if virtualenv not yet installed then no worry - plugin will install the correct version)
Linux/Macos install
On most *nix distributions python is already installed, but often without pip.
Install pip if required (ubuntu example):
sudo apt-get install python3-pip
Make sure the latest pip installed (required to overcome some older pip problems):
pip3 install -U pip
To install exact pip version:
pip3 install -U pip==20.0.11
Note that on ubuntu pip installed with python3-pip
package is 9.0.1, but it did not(!) downgrade module versions (e.g. pip install click 6.6
when click 6.7 is installed will do nothing). Maybe there are other differences, so it's highly recommended to upgrade pip with pip3 install -U pip
.
Automatic pip upgrade
As described above, there are different ways of pip installation in linux and, more important, admin permissions are required to upgrade global pip. So it is impossible to upgrade pip from the plugin (in all cases).
But, it is possible inside virtualenv or user (--user) scope. Note that plugin creates virtualenv by default (per project independent python environment).
So, in order to use newer pip simply put it as first dependency:
python {
pip 'pip:10.0.1'
pip 'some_module:1.0'
}
Here project virtualenv will be created with global pip and newer pip version installed inside environment. Packages installation is sequential, so all other packages will be installed with newer pip (each installation is independent pip command).
The same will work for user scope: python.scope = USER
When applying this trick, consider minimal pip version declared in configuration (python.minPipVersion='9'
by default) as minimal pip version required for project setup (instead of minimal version required for work).
Automatic python install
Python is assumed to be used as java: install and forget. It perfectly fits user use case: install python once and plugin will replace all manual work on project environment setup.
It is also easy to configure python on CI (like travis).
If you want automatic python installation, try looking on JetBrain's python-envs plugin. But be careful because it has some caveats (for example, on windows python could be installed automatically just once and requires manual un-installation).
Multi-module projects
When used in multi-module project, plugin will create virtualenv inside the root project directory in order to share the same environment for all modules.
Travis CI configuration
To make plugin work on travis you'll need to install python3 packages:
language: java
dist: bionic
jdk: openjdk8
addons:
apt:
packages:
- "python3"
- "python3-pip"
- "python3-setuptools"
before_install:
- pip3 install -U pip
It will be python 3.6 by default (for bionic).
Appveyour CI configuration
To make plugin work on appveyour you'll need to add python to path:
environment:
matrix:
- JAVA_HOME: C:\Program Files\Java\jdk1.8.0
PYTHON: "C:\\Python36-x64"
install:
- set PATH=%PYTHON%;%PYTHON%\\Scripts;%PATH%
- python --version
Now plugin would be able to find python binary.
To use python 3.9 you'll need to switch image:
image: Visual Studio 2019
See available pythons matrix for more info.
Usage
Declare required modules (optional):
python.pip 'module1:1.0', 'module2:1.0'
or
python {
pip 'module1:1.0'
pip 'module2:1.0'
}
Module format is: name:version
(will mean name==version
in pip notion). Non strict version definition is not allowed (for obvious reasons). Dependencies are installed in declaration order. If duplicate declaration specified then only the latest declaration will be used:
python.pip 'module1:2.0', 'module2:1.0', 'module1:1.0'
Will install version 1.0 of module1 because it was the latest declaration. "Module overrides" works for all declaration types (see below): the latest declared module version always wins.
Dependencies are installed with pipInstall
task which is called before any declared PythonTask
.
Note that by default dependencies are installed inside project specific virtualenv (project specific copy of python environment).
Behaviour matrix for possible scope
and installVirtualenv
configurations:
scope | installVirtualenv | Behaviour | default |
---|---|---|---|
GLOBAL | ignored | packages installed in global scope (pip install name ) |
|
USER | ignored | packages installed in user scope (pip install name --user ) |
|
VIRTUALENV_OR_USER | true | if virtualenv not installed, install it in user scope; create project specific virtualenv and use it | default |
VIRTUALENV_OR_USER | false | when virtualenv is not installed install packages in user scope (same as USER); when virtualenv installed create project specific virtualenv and use it | |
VIRTUALENV | true | if virtualenv not installed, install it in user scope; create project specific virtualenv and use it | |
VIRTUALENV | false | throw error when virtualenv not installed |
Note that VIRTUALENV + true
and VIRTUALENV_OR_USER + true
behaviours are the same. Different scope name here describes behavior for unexpected installVirtualenv=false
change (to fail or fallback to user scope).
USER
and GLOBAL
scopes will ignore local (virtual)environment, even if project-specific environment was created before, with these options global python will be used instead.
Pip module extra features
You can declare modules with extra features in module name to install special version of module (with enabled features):
python.pip 'requests[socks,security]:2.18.4'
IMPORTANT: it is impossible to track if this "variation" of module is installed, so plugin performs up-to-date check for such modules by name only (for example, if 'requests==2.18.4' is already installed). For most cases, this is suitable behaviour because, by default, modules are installed in virtualenv and so you will always have correct module installed. For other cases, you can disable up-to-date checks (delegate all dependencies logic to pip): python.alwaysInstallModules = true
VCS pip modules
You can declare vcs modules: modules installed directly from version control (e.g. git, svn). Format:
vcs+protocol://repo_url/@vcsVersion#egg=pkg-pkgVersion
@vcsVersion
part is required: prefer using commit version or tag for reproducible builds-pkgVersion
is installed module version. Required to be able to compare declared plugin with installed version.
For example:
python.pip 'git+https://github.com/ictxiangxin/boson/@b52727f7170acbedc5a1b4e1df03972bd9bb85e3#egg=boson-0.9'
Declares module boson
version 0.9
, installed from git commit b52727f7170acbedc5a1b4e1df03972bd9bb85e3
(it may be tag name or branch, but prefer not using branch names).
pipInstall
will be considered up-to-date if boson==0.9
is already installed. Note that declared module version is completely free: you can set any version (0.10, 1.2, etc.), it is not checked and used only for up-to-date validation.
WARNING: module version part assumed to follow the last dash, so if you specify version like somethinf-12.0-alpha.1
it would be parsed incorrectly (as package somethinf-12.0
version alpha.1
)! Don't use dashes in a version!
Vcs module installation is: source checkout and module build (using setup.py). You may need to specify subdirectory as &subdirectory=pkg_dir
(see docs)
To avoid installation problems, package version is not used for actual installation (in spite of the fact that its official convention, it doesnt work in some cases). For example, module above will be installed as (no -0.9
):
pip install git+https://github.com/ictxiangxin/boson/@b52727f7170acbedc5a1b4e1df03972bd9bb85e3#egg=boson
All pip supported vcs could be used: git, svn, hg, bzr
If up-to-date logic, implemented by pipInstall
task, does not suit your needs, you can always disable it with python.alwaysInstallModules = true
(pip always called). But this will be slower.
NOTE: since pip 20, compiled vcs module is cached (before it was build on each execution), but it is possible to disable cache (for all modules) with python.usePipCache=false
configuration (applies --no-cache-dir pip flag)
Extra pip repositories
To add additional pip repositories (probably self-hosted):
python {
extraIndexUrls = ["http://extra-url.com", "http://extra-url.com"]
}
or with shortcut method (shortcut may be used multiple times):
python {
extraIndexUrls "http://extra-url.com", "http://extra-url2.com"
}
Extra urls will be applied as --extra-index-url flag for pip commands supporting it: install, download, list and wheel. By default, it only affects pipInstall
and pipList
tasks. Applied for all BasePipTask
, so if you have custom pip tasks, it would be affected too.
In case of ssl problems (stale or self-signed certificated), mark domains as trusted:
python {
trustedHosts = ["extra-url.com"]
}
or
python {
trustedHosts "extra-url.com"
}
Applied as --trusted-host option only for pipInstall
(because pip install
is the only command supporting this option).
NOTE: if, for some reason, you don't want to specify it for all pip tasks, you can configure exact task, for example: pipInstall.extraIndexUrls = ["http://extra-url.com", "http://extra-url2.com"]
Extra pip install options
It is impossible to support directly all possible pip install
options usages directly with api (safe way), so there is a direct configuration for an additional options. For example:
pipInstall.options('--upgrade-strategy', 'only-if-needed')
Shortcut method above may be called multiple times:
pipInstall.options('--a', 'value')
pipInstall.options('--b', 'value')
Or you can use property directly:
pipInstall.options = ['--a', 'value', '--b', 'value']
Virtualenv
When you declare any pip modules, plugin will try to use virtualenv in order to install required modules locally (for current project only).
If virtualenv is not installed - it will be installed automatically in --user
scope. If you don't want automatic installation then disable it:
python.installVirtualenv = false
Plugin installs exact pip version declared in python.virtualenvVersion
(by default, 16.7.9). This way, plugin will always install only known to be working version and avoid side effects of "just released" versions (note that pip 20 is a major rewrite and may still contain side effects).
In any case, plugin checks if virtualenv is already installed and use it to create local environment (if not, then fall back to --user
scope by default). Virtualenv usage is driven by declared scope, so if you don't want to use it set:
python.scope = USER // or GLOBAL
With USER (or GLOBAL) scope, virtualenv will not be used, even if it's already created in project (plugin will ignore it and use global python).
If you already use virtualenv in your project (have created manually environment), then simply point plugin to use it:
python.envPath = 'path/to/your/env'
It will automatically change pythonPath
configuration accordingly.
NOTE: plugin will not create environment if you don't use any modules. If you still want to use project specific environment (without declared pip modules) then create it manually: python3 -m virtualenv .gradle/python
(default location). Plugin will recognize existing env and use it.
IMPORTANT: virtualenv creates local python copy (by default in .gradle/python
). Copy is created from global python and later used instead of global python. If you want to change used python version in the environment, then manually remove .gradle/python
so it could be created again (from global python).
To copy environment instead of symlinking (default) set (--always-copy):
python.envCopy = true
Scope
Pip dependencies could be installed per project, for current user (~/) or globally.
Default behaviour:
- if
virtualenv
module installed (or automatically installed, see above): manage pip dependencies per project (env.gradle/python
created) - if no virtualenv - use user scope (
--user
pip flag): pip modules are installed only for current user (this avoid permission problems on linux)
To change defaults:
python.scope = VIRTUALENV
GLOBAL
- install modules globally (this may not work on linux due to permissions)USER
- use--user
flag to install for current user onlyVIRTUALENV_OR_USER
- defaultVIRTUALENV
- usevirtualenv
(if module not installed - error thrown)
Note that values may be declared without quotes because it's an enum which values are declared as project ext properties (ext.USER==ru.vyarus.gradle.plugin.python.PythonExtension.Scope.USER
).
Complete behaviour matrix see above
Check modules updates
To quick check if new versions are available for the registered pip modules use pipUpdates
task:
:pipUpdates
The following modules could be updated:
package version latest type
------------------ ------- ------ -----
click 6.6 6.7 wheel
Note that it will not show versions for transitive modules, only for modules specified directly in python.pip
.
To see all available updates (without filtering):
pipUpdates.all = true
NOTE: If you see an error like
TypeError: '>' not supported between instances of 'Version' and 'SetuptoolsVersion'
then update pip:
pip install -U pip
Call python
Call python command:
task cmd(type: PythonTask) {
command = "-c print('sample')"
}
called: python -c print('sample')
on win and python -c exec("print('sample')")
on *nix (exec applied automatically for compatibility)
Call multi-line command:
task cmd(type: PythonTask) {
command = "-c \"import sys; print(sys.prefix)\""
}
called: python -c "import sys; print(sys.prefix)"
on win and python -c exec("import sys; print(sys.prefix)")
on *nix
NOTE: it is important to wrap script with space in quotes (otherwise parser will incorrectly parse arguments).
Call module:
task mod(type: PythonTask) {
module = 'sample'
command = "mod args"
}
called: python -m sample mod args
Call script:
task script(type: PythonTask) {
command = "path/to/script.py 1 2"
}
called: python path/to/script.py 1 2
(arguments are optional, just for demo)
String command is used for simplicity, but it could be array/collection of args:
task script(type: PythonTask) {
command = ['path/to/script.py', '1', '2']
}
Command parsing
When command passed as string it is manually parsed to arguments array (split by space):
- Spaces in quotes are ignored:
"quoted space"
or'quoted space'
- Escaped spaces are ignored:
with\\ space
(argument will be used with simple space then - escape removed). - Escaped quotes are ignored:
"with \\"interrnal quotes\\" inside"
. But pay attention that it must be 2 symbols\\"
and not\"
because otherwise it is impossible to detect escape.
To view parsed arguments run gradle with -i
flag (enable info logs). In case when command can't be parsed properly (bug in parser or unsupported case) use array of arguments instead of string.
Environment variables
By default, executed python can access system environment variables (same as System.getenv()
).
To declare custom (process specific) variables:
task sample(type: PythonTask) {
command = "-c \"import os;print('variables: '+os.getenv('some', 'null')+' '+os.getenv('foo', 'null'))\""
environment 'some', 1
environment 'other', 2
environment(['foo': 'bar', 'baz': 'bag'])
}
Map based declaration (environment(['foo': 'bar', 'baz': 'bag'])
) does not remove previously declared variables (just add all vars from map), but direct assignment environment = ['foo': 'bar', 'baz': 'bag']
will reset variables.
System variables will be available even after declaring custom variables (of course, custom variables could override global value).
NOTE: environment variable could also be declared in extension to apply for all python commands: python.environment 'some', 1
(if environments declared both globally (through extension) and directly on task, they would be merged)
Configuration
Python location
On linux, plugin will use python3
if available (and fall back to python
if not). To use different binary use:
python {
pythonBinary = 'python'
}
This will force python 2 for linux. Also, this may be handy if python binary is named differently.
To use non global python:
python {
pythonPath = 'path/to/python/binray/'
}
pythonPath
must be set to directory containing python binary (e.g. 'path/to/python/binray/python.exe')
NOTE: pythonPath
is ignored when virtualenv used (virtualenv located at python.envPath
already exists).
Minimal python and pip versions
To set python version constraint:
python {
minPythonVersion = '3.2'
}
Python version format is: major.minor.micro. Constraint may include any number of levels: '3', '3.1', '2.7.5'
The same way pip version could be restricted:
python {
minPipVersion = '9.0.1'
}
Pip
By default, all installed python modules are printed to console after pip installations using pip list
(of course, if at least one module declared for installation). This should simplify problems resolution (show used transitive dependencies versions).
To switch off:
python {
showInstalledVersions = false
}
You can always see the list of installed modules with pipList
task (exactly the same list as after pipInstall).
NOTE: if global python is used with USER scope and some modules were manually installed in global scope then they will not be shown by pipList (and after pip install). To see all modules:
pipList.all = true
Global modules are hidden by default (for USER scope) because on linux there are a lot of system modules pre-installed.
By default, 'pip install' is not called for modules already installed with correct version. In most situations this is preferred behaviour, but if you need to be sure about dependencies then force installation:
python {
alwaysInstallModules = true
}
Reference
All configuration options with default values:
python {
// path to python binary (global by default)
pythonPath
// python binary name (python or python3 by default)
pythonBinary
// additional environment variables, visible for all python commands
environment = [:]
// minimal required python version (m.m.m)
minPythonVersion
// minimal required pip version (m.m.m)
minPipVersion = '9'
// show all installed modules versions after pip installation
showInstalledVersions = true
// always call module install, even if correct version is already installed
alwaysInstallModules = false
// may be used to disable pip cache (--no-cache-dir option)
usePipCache = true
// additional pip repositories (--extra-index-url option)
extraIndexUrls = []
// trusted hosts for pip install (--trusted-host option)
trustedHosts = []
// pip modules installation scope (project local, os user dir, global)
scope = VIRTUALENV_OR_USER
// automatically install virtualenv module (if pip modules declared and scope allows)
installVirtualenv = true
// if virtualenv not installed (in --user scope), plugin will install exactly this version
// (known to be working version) to avoid side effects
virtualenvVersion = '20.4.2'
// minimal required virtualenv (v20 is recommended, but by default 16 set to not fail previous
// setups)
minVirtualenvVersion = '16'
// used virtualenv path (if virtualenv used, see 'scope')
envPath = '.gradle/python'
// copy virtualenv instead of symlink (when created)
envCopy = false
}
Note that in case of multi-module project envPath is set to '.gradle/python' inside the root project, even if plugin is activated inside module (see multi-module setup).
PythonTask
PythonTask configuration:
Property | Description |
---|---|
pythonPath | Path to python binary. By default used path declared in global configuration |
pythonBinary | Python binary name. By default, python3 on linux and python otherwise. |
workDir | Working directory (important if called script/module do file operations). By default, it's a project root |
createWorkDir | Automatically create working directory if does not exist. Enabled by default |
module | Module name to call command on (if command not set module called directly). Useful for derived tasks. |
command | Python command to execute (string, array, iterable) |
logLevel | Logging level for python output. By default is LIFECYCLE (visible in console). To hide output use LogLevel.INFO |
pythonArgs | Extra python arguments applied just after python binary. Useful for declaring common python options (-I, -S, etc.) |
extraArgs | Extra arguments applied at the end of declared command (usually module arguments). Useful for derived tasks to declare default options |
outputPrefix | Prefix, applied for each line of python output. By default is '\t' to identify output for called gradle command |
environment | Process specific environment variables |
Also, task provide extra methods:
pythonArgs(String... args)
to declare extra python arguments (shortcut to append values to pythonArgs property).extraArgs(String... args)
to declare extra arguments (shortcut to append values to extraArgs property).environment(String var, Object value)
to set custom environment variable (shortcut to append values to environment property)environment(Map<String, Object> vars)
to set multiple custom environment variables at once (shortcut to append values to environment property)
PipInstallTask
Default pip installation task is registered as pipInstall
and used to install modules, declared in global configuration. Custom task(s) may be used, if required:
task myPipInst(type: PipInstallTask) {
pip 'mod:1', 'other:2'
}
Configuration:
Property | Description |
---|---|
pythonPath | Path to python binary. By default used path declared in global configuration |
pythonBinary | Python binary name. By default, python3 on linux and python otherwise. |
pythonArgs | Extra python arguments applied just after python binary. Useful for declaring common python options (-I, -S, etc.) |
environment | Process specific environment variables |
modules | Modules to install. In most cases configured indirectly with pip(..) task methods. By default, modules from global configuration. |
userScope | Use current user scope (--user flag). Enabled by default to avoid permission problems on *nix (global configuration). |
showInstalledVersions | Perform pip list after installation. By default use global configuration value |
alwaysInstallModules | Call pip install module for all declared modules, even if it is already installed with correct version. By default use global configuration value |
useCache | Can be used to disable pip cache (--no-cache-dir) |
extraIndexUrls | Additional pip repositories (--extra-index-url) |
/ trustedHosts / trusted hosts (--trusted-host) / | |
/ options / additional pip install options / |
And, as shown above, custom methods:
pip(String... modules)
pip(Iterable<String> modules)
options(String... options)
Use as base for specific module plugin
Plugin supposed to be used as base for plugins for specific python modules. With it you don't need to implement modules installation and could use provided abstractions to call python.
Example usage: gradle-mkdocs-plugin.
In your plugin, add plugin as dependency:
dependencies {
implementation 'ru.vyarus:gradle-use-python-plugin:2.3.0'
}
And apply plugin: project.plugins.apply(PythonPlugin)
(required to register python
extension and declare default pipInstall task).
Extended task
The simplest way is to extend PythonTask
:
class SomeModuleTask extends PythonTask {
@Override
String getModule() {
// always call specified commands on module
return 'somemodule'
}
@Override
List<String> getExtraArgs() {
// example of module options configuration with custom extension
def res = []
SomeModuleExtension ext = project.extensions.getByType(SomeModuleExtension)
if (ext.somOption) {
res << '--option'
}
return res
}
// optionally apply extra behaviour
@Override
void run() {
// before python call
super.run()
// after python call
}
}
Usage:
pyton.pip 'sommemodule:1'
task modCmd(type: SomeModuleTask) {
command = 'module args'
}
called: python -m somemodule module arfs --option
In some cases, you can use BasePythonTask
which is a super class of PythonTask
and provides only automatic pythonPath
and pythonBinary
properties set from global configuration.
Completely custom task
Plugin provides ru.vyarus.gradle.plugin.python.cmd.Python
utility class, which could be used directly in custom task (PythonTask
is a wrapper above the utility).
Example usage:
Python python = new Python(project, getPythonPath(), getPythonBinary())
.logLevel(getLogLevel())
.outputPrefix(getOutputPrefix())
.workDir(getWorkDir())
.extraArgs(getExtraArgs())
// execute and get command output
String out = python.readOutput(cmd)
// call module (the same as exec() but applies '-m mod' before command)
python.callModule('mod', cmd)
// direct python call
python.exec(cmd)
This could be used directly in the completely custom task.
Specific utility for target module could be defined, see ru.vyarus.gradle.plugin.python.cmd.Pip
util as an example (simplified):
class Pip {
private final Python python
Pip(Project project, String pythonPath, String binary) {
// configure custom python execution util
python = new Python(project, pythonPath, binary)
.logLevel(LogLevel.LIFECYCLE)
}
// declare module specific commands
void install(String module) {
python.callModule('pip', "install $module")
}
}
Apply default modules
In your plugin you could apply default modules like this:
afterEvaluate {
PythonExtension ext = project.extensions.getByType(PythonExtension)
// delayed default module(s) declaration based on user configuration
if (!ext.isModuleDeclared('somemodule')) {
ext.pip 'sommemodule:1'
}
}
Or always declare default modules (before configuration):
PythonExtension ext = project.extensions.getByType(PythonExtension)
ext.pip 'sommeodule:1', 'othermodule:2'
User will be able to override default versions by direct module declaration (even downgrade version):
python.pip 'sommodule:0.9'
NOTE: all pip declarations are supported so direct module version could be overridden with VCS declaration and vice-versa (only the declaration order is important).
Hide sensitive data in logged command
By default, plugin always logs executed python commands, but sometimes such commands could contain sensitive data (like passwords).
For example, pip's --extra-index-url may contain password:
--extra-index-url http://user:[email protected]
In logged command password should be replaced with *****.
To deal with such cases, Python object supports registration of LoggedCommandCleaner
object:
python.logCommandCleaner(new CleanerInstance)
As an example see Pip object, which register special cleaner for extra index passwords right in its constructor:
Pip(Python python, boolean userScope, boolean useCache) {
...
// do not show passwords when external indexes used with credentials
python.logCommandCleaner { CliUtils.hidePipCredentials(it) }
}
See CliUtils.hidePipCredentials
for an implementation example (using regexps). Most likely, implementation would be the same in your case.
Might also like
- quality-plugin - java and groovy source quality checks
- animalsniffer-plugin - java compatibility checks
- pom-plugin - improves pom generation
- java-lib-plugin - avoid boilerplate for java or groovy library project
- github-info-plugin - pre-configure common plugins with github related info