diff --git a/.flake8 b/.flake8
new file mode 100644
index 0000000..1fd4893
--- /dev/null
+++ b/.flake8
@@ -0,0 +1,2 @@
+[flake8]
+max-line-length = 160
diff --git a/library/intellij_configure_jdk.py b/library/intellij_configure_jdk.py
index e7aabe3..2eecaa9 100644
--- a/library/intellij_configure_jdk.py
+++ b/library/intellij_configure_jdk.py
@@ -1,22 +1,15 @@
-#!/usr/bin/python
+#!/usr/bin/env python3
-# Make coding more python3-ish
-from __future__ import (absolute_import, division, print_function)
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils._text import to_bytes, to_native
-from distutils.version import LooseVersion
-import zipfile
-import xml.sax.saxutils
-import pwd
import grp
import os
-__metaclass__ = type
+import pwd
+import xml.sax.saxutils
+import zipfile
+from pathlib import Path
+from typing import Dict, Tuple
-ANSIBLE_METADATA = {
- 'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'community'
-}
+from ansible.module_utils.basic import AnsibleModule
+from ansible.module_utils.compat.version import LooseVersion
DOCUMENTATION = '''
---
@@ -74,83 +67,75 @@
HAS_LXML = False
-def pretty_print(elem):
- text = etree.tostring(elem, encoding='iso-8859-1')
+def pretty_print(elem: etree.Element) -> str:
+ text = etree.tostring(elem, encoding='unicode')
parser = etree.XMLParser(remove_blank_text=True)
xml = etree.fromstring(text, parser)
- return etree.tostring(xml,
- encoding='iso-8859-1',
- pretty_print=True,
- xml_declaration=False)
+ return etree.tostring(xml, encoding='unicode', pretty_print=True, xml_declaration=False)
-def get_java_version(module, jdk_home):
- executable = os.path.join(jdk_home, 'bin', 'java')
- if not os.path.isfile(executable):
- module.fail_json(msg='File not found: %s' % executable)
+def get_java_version(module: AnsibleModule, jdk_home: Path) -> str:
+ executable = jdk_home / 'bin' / 'java'
+ if not executable.is_file():
+ module.fail_json(msg=f'File not found: {executable}')
- rc, out, err = module.run_command([executable, '-version'])
+ rc, out, err = module.run_command([str(executable), '-version'])
if rc != 0:
- module.fail_json(msg='Error while querying Java version: %s' %
- (out + err))
+ module.fail_json(msg=f'Error while querying Java version: {out + err}')
return err.splitlines()[0]
-def get_class_path(module, jdk_home):
- jre_lib = os.path.join(jdk_home, 'jre', 'lib')
+def get_class_path(module: AnsibleModule, jdk_home: Path) -> str:
+ jre_lib = jdk_home / 'jre' / 'lib'
- jre_ext = os.path.join(jre_lib, 'ext')
+ jre_ext = jre_lib / 'ext'
- jmods = os.path.join(jdk_home, 'jmods')
+ jmods = jdk_home / 'jmods'
- if os.path.isdir(jre_ext):
+ if jre_ext.is_dir():
- files = [os.path.join(jre_lib, x) for x in os.listdir(jre_lib)]
- files = files + [os.path.join(jre_ext, x) for x in os.listdir(jre_ext)]
+ files = list(jre_lib.iterdir()) + list(jre_ext.iterdir())
- files = [x for x in files if os.path.isfile(x) and x.endswith('.jar')]
+ files = [x for x in files if x.is_file() and x.suffix == '.jar']
files = sorted(files)
- urls = ['jar://%s!/' % x for x in files]
+ urls = [f'jar://{str(x)}!/' for x in files]
- elements = [
- '' % xml.sax.saxutils.quoteattr(x)
- for x in urls
- ]
+ elements = [f'' for x in urls]
return "\n".join(elements)
- elif os.path.isdir(jmods):
+ elif jmods.is_dir():
- files = [os.path.join(jmods, x) for x in os.listdir(jmods)]
+ files = list(jmods.iterdir())
- files = [x for x in files if os.path.isfile(x) and x.endswith('.jmod')]
+ files = [x for x in files if x.is_file() and x.suffix == '.jmod']
- module_names = [os.path.basename(x)[:-5] for x in files]
+ module_names = [x.stem for x in files]
module_names = sorted(module_names)
- urls = ['jrt://%s!/%s' % (jdk_home, x) for x in module_names]
+ urls = [f'jrt://{jdk_home}!/{x}' for x in module_names]
- elements = [
- '' % xml.sax.saxutils.quoteattr(x)
- for x in urls
- ]
+ elements = [f'' for x in urls]
return "\n".join(elements)
else:
module.fail_json(
- msg=("Unsupported JDK directory layout: %s. If you're "
- "using Java > 9 you may need to install the "
- "jmods package e.g. yum install "
- "java-11-openjdk-jmods.") % jdk_home)
+ msg=(
+ f"Unsupported JDK directory layout: {jdk_home}. If you're "
+ "using Java > 9 you may need to install the "
+ "jmods package e.g. yum install "
+ "java-11-openjdk-jmods."
+ )
+ )
-def get_source_path(module, jdk_home):
- jmod_src = os.path.join(jdk_home, 'lib', 'src.zip')
+def get_source_path(module: AnsibleModule, jdk_home: Path) -> str:
+ jmod_src = jdk_home / 'lib' / 'src.zip'
- if os.path.isfile(jmod_src):
+ if jmod_src.is_file():
with zipfile.ZipFile(jmod_src, 'r') as srczip:
files = srczip.namelist()
@@ -161,135 +146,108 @@ def get_source_path(module, jdk_home):
module_names = sorted(module_names)
- urls = [
- 'jar://%s/lib/src.zip!/%s' % (jdk_home, x) for x in module_names
- ]
+ urls = [f'jar://{jdk_home / "lib" / "src.zip"}!/{x}' for x in module_names]
- elements = [
- '' % xml.sax.saxutils.quoteattr(x)
- for x in urls
- ]
+ elements = [f'' for x in urls]
return "\n".join(elements)
- elif os.path.isdir(jdk_home):
+ elif jdk_home.is_dir():
- files = [os.path.join(jdk_home, x) for x in os.listdir(jdk_home)]
+ files = list(jdk_home.iterdir())
- files = [
- x for x in files if os.path.isfile(x) and x.endswith('src.zip')
- ]
+ files = [x for x in files if x.is_file() and x.name.endswith('src.zip')]
files = sorted(files)
- urls = ['jar://%s!/' % x for x in files]
+ urls = [f'jar://{x}!/' for x in files]
- elements = [
- '' % xml.sax.saxutils.quoteattr(x)
- for x in urls
- ]
+ elements = [f'' for x in urls]
return "\n".join(elements)
else:
- module.fail_json(msg='Directory not found: %s' % jdk_home)
-
-
-def create_jdk_xml(module, intellij_user_config_dir, jdk_name, jdk_home):
- params = {
- 'jdk_name':
- xml.sax.saxutils.quoteattr(jdk_name),
- 'java_version':
- xml.sax.saxutils.quoteattr(get_java_version(module, jdk_home)),
- 'jdk_home':
- xml.sax.saxutils.quoteattr(jdk_home),
- 'class_path':
- get_class_path(module, jdk_home),
- 'source_path':
- get_source_path(module, jdk_home)
- }
-
- return etree.fromstring('''
-
-
-
-
-
-
-
-
-
-
-
-
- %(class_path)s
-
-
-
-
-
- %(source_path)s
-
-
-
- ''' % params)
-
-
-def make_dirs(path, mode, uid, gid):
- dirs = [path]
- dirname = os.path.dirname(path)
- while dirname != '/':
- dirs.insert(0, dirname)
- dirname = os.path.dirname(dirname)
-
- for dirname in dirs:
- if not os.path.exists(dirname):
- os.mkdir(dirname, mode)
- os.chown(dirname, uid, gid)
-
-
-def configure_jdk(module, intellij_user_config_dir, jdk_name, jdk_home, uid,
- gid):
- options_dir = os.path.join(intellij_user_config_dir, 'options')
-
- project_default_path = os.path.join(options_dir, 'jdk.table.xml')
-
- create_jdk_table = (not os.path.isfile(project_default_path)
- ) or os.path.getsize(project_default_path) == 0
+ module.fail_json(msg=f'Directory not found: {jdk_home}')
+
+
+def create_jdk_xml(module: AnsibleModule, jdk_name: str, jdk_home: Path) -> etree.Element:
+ java_version = get_java_version(module, jdk_home)
+ class_path = get_class_path(module, jdk_home)
+ source_path = get_source_path(module, jdk_home)
+
+ return etree.fromstring(f'''
+
+
+
+
+
+
+
+
+
+
+
+
+ {class_path}
+
+
+
+
+
+ {source_path}
+
+
+
+''')
+
+
+def make_dirs(path: Path, mode: int, uid: int, gid: int) -> None:
+ dirs = []
+ current = path
+ while not current.exists():
+ dirs.append(current)
+ current = current.parent
+ dirs.reverse()
+ for dirpath in dirs:
+ dirpath.mkdir(mode=mode)
+ os.chown(str(dirpath), uid, gid)
+ dirpath.chmod(mode)
+
+
+def configure_jdk(module: AnsibleModule, intellij_user_config_dir: Path, jdk_name: str, jdk_home: Path, uid: int, gid: int) -> Tuple[bool, Dict[str, str]]:
+ options_dir = intellij_user_config_dir / 'options'
+ project_default_path = options_dir / 'jdk.table.xml'
+
+ create_jdk_table = (not project_default_path.is_file()) or project_default_path.stat().st_size == 0
if create_jdk_table:
if not module.check_mode:
- if not os.path.isdir(options_dir):
+ if not options_dir.is_dir():
make_dirs(options_dir, 0o775, uid, gid)
- if not os.path.isfile(project_default_path):
- with open(project_default_path, 'wb', 0o664) as xml_file:
- xml_file.write(to_bytes(''))
- os.chown(project_default_path, uid, gid)
+ if not project_default_path.is_file():
+ project_default_path.touch()
+ os.chown(str(project_default_path), uid, gid)
+ project_default_path.chmod(0o664)
jdk_table_root = etree.Element('application')
jdk_table_doc = etree.ElementTree(jdk_table_root)
before = ''
else:
- jdk_table_doc = etree.parse(project_default_path)
+ jdk_table_doc = etree.parse(str(project_default_path))
jdk_table_root = jdk_table_doc.getroot()
before = pretty_print(jdk_table_root)
if jdk_table_root.tag != 'application':
- module.fail_json(msg='Unsupported root element: %s' %
- jdk_table_root.tag)
+ module.fail_json(msg=f'Unsupported root element: {jdk_table_root.tag}')
- project_jdk_table = jdk_table_root.find(
- './component[@name="ProjectJdkTable"]')
+ project_jdk_table = jdk_table_root.find('./component[@name="ProjectJdkTable"]')
if project_jdk_table is None:
- project_jdk_table = etree.SubElement(jdk_table_root,
- 'component',
- name='ProjectJdkTable')
+ project_jdk_table = etree.SubElement(jdk_table_root, 'component', name='ProjectJdkTable')
- new_jdk = create_jdk_xml(module, intellij_user_config_dir, jdk_name,
- jdk_home)
+ new_jdk = create_jdk_xml(module, jdk_name, jdk_home)
new_jdk_string = pretty_print(new_jdk)
- old_jdk = project_jdk_table.find('./jdk/name[@value="%s"]/..' % jdk_name)
+ old_jdk = project_jdk_table.find(f'./jdk/name[@value="{jdk_name}"]/..')
if old_jdk is None:
old_jdk_string = ''
changed = True
@@ -303,20 +261,19 @@ def configure_jdk(module, intellij_user_config_dir, jdk_name, jdk_home, uid,
after = pretty_print(jdk_table_root)
if changed and not module.check_mode:
- with open(project_default_path, 'wb') as xml_file:
- xml_file.write(to_bytes(after))
-
- return changed, {'before:': before, 'after': after}
+ project_default_path.write_text(after, encoding='iso-8859-1')
+ return changed, {'before': before, 'after': after}
-def run_module():
- module_args = dict(intellij_user_config_dir=dict(type='str',
- required=True),
- jdk_name=dict(type='str', required=True),
- jdk_home=dict(type='str', required=True),
- owner=dict(type='str', required=True),
- group=dict(type='str', required=True))
+def run_module() -> None:
+ module_args = dict(
+ intellij_user_config_dir=dict(type='str', required=True),
+ jdk_name=dict(type='str', required=True),
+ jdk_home=dict(type='str', required=True),
+ owner=dict(type='str', required=True),
+ group=dict(type='str', required=True)
+ )
module = AnsibleModule(argument_spec=module_args, supports_check_mode=True)
@@ -326,48 +283,45 @@ def run_module():
try:
uid = int(owner)
except ValueError:
- uid = pwd.getpwnam(owner).pw_uid
+ try:
+ uid = pwd.getpwnam(owner).pw_uid
+ except KeyError:
+ module.fail_json(msg=f"User '{owner}' does not exist")
username = pwd.getpwuid(uid).pw_name
try:
gid = int(group)
except ValueError:
- gid = grp.getgrnam(group).gr_gid
+ try:
+ gid = grp.getgrnam(group).gr_gid
+ except KeyError:
+ module.fail_json(msg=f"Group '{group}' does not exist")
- intellij_user_config_dir = os.path.expanduser(
- os.path.join('~' + username,
- module.params['intellij_user_config_dir']))
+ intellij_user_config_dir = Path('~' + username, module.params['intellij_user_config_dir']).expanduser()
jdk_name = module.params['jdk_name']
- jdk_home = os.path.expanduser(module.params['jdk_home'])
+ jdk_home = Path(module.params['jdk_home']).expanduser()
# Check if we have lxml 2.3.0 or newer installed
if not HAS_LXML:
- module.fail_json(
- msg='The xml ansible module requires the lxml python '
- 'library installed on the managed machine')
- elif LooseVersion('.'.join(
- to_native(f) for f in etree.LXML_VERSION)) < LooseVersion('2.3.0'):
- module.fail_json(
- msg='The xml ansible module requires lxml 2.3.0 or newer installed'
- ' on the managed machine')
- elif LooseVersion('.'.join(
- to_native(f) for f in etree.LXML_VERSION)) < LooseVersion('3.0.0'):
- module.warn(
- 'Using lxml version lower than 3.0.0 does not guarantee '
- 'predictable element attribute order.')
+ module.fail_json(msg='The xml ansible module requires the lxml python library installed on the managed machine')
+ else:
+ lxml_version = LooseVersion('.'.join(str(f) for f in etree.LXML_VERSION))
+ if lxml_version < LooseVersion('2.3.0'):
+ module.fail_json(msg='The xml ansible module requires lxml 2.3.0 or newer installed on the managed machine')
+ elif lxml_version < LooseVersion('3.0.0'):
+ module.warn('Using lxml version lower than 3.0.0 does not guarantee predictable element attribute order.')
- changed, diff = configure_jdk(module, intellij_user_config_dir, jdk_name,
- jdk_home, uid, gid)
+ changed, diff = configure_jdk(module, intellij_user_config_dir, jdk_name, jdk_home, uid, gid)
if changed:
- msg = 'JDK %s has been configured' % jdk_name
+ msg = f'JDK {jdk_name} has been configured'
else:
- msg = 'JDK %s was already configured' % jdk_name
+ msg = f'JDK {jdk_name} was already configured'
module.exit_json(changed=changed, msg=msg, diff=diff)
-def main():
+def main() -> None:
run_module()
diff --git a/library/intellij_install_plugin.py b/library/intellij_install_plugin.py
index b9d748d..626c3fa 100644
--- a/library/intellij_install_plugin.py
+++ b/library/intellij_install_plugin.py
@@ -1,39 +1,22 @@
-#!/usr/bin/python
-
-# Make coding more python3-ish
-from __future__ import (absolute_import, division, print_function)
-from ansible.module_utils.urls import ConnectionError, NoSSLError, open_url
-from ansible.module_utils.basic import AnsibleModule, get_distribution
-from ansible.module_utils._text import to_native
-from ansible.module_utils.six import PY3
-import ansible.module_utils.six.moves.urllib.error as urllib_error
-from distutils.version import LooseVersion
-import zipfile
-import traceback
-import time
-import tempfile
-import socket
-import shutil
-import re
-import pwd
-import os
-import json
-import hashlib
-import grp
-
-try:
- import httplib
-except ImportError:
- # Python 3
- import http.client as httplib
+#!/usr/bin/env python3
-__metaclass__ = type
+import grp
+import hashlib
+import json
+import os
+import pwd
+import re
+import shutil
+import tempfile
+import time
+import urllib.parse
+import zipfile
+from pathlib import Path
+from typing import Any, Optional, Tuple
-ANSIBLE_METADATA = {
- 'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'community'
-}
+from ansible.module_utils.basic import AnsibleModule
+from ansible.module_utils.compat.version import LooseVersion
+from ansible.module_utils.urls import fetch_url
DOCUMENTATION = '''
---
@@ -97,178 +80,74 @@
except ImportError:
HAS_LXML = False
-try:
- from ansible.module_utils.six.moves.urllib.parse import urlencode, urljoin
- HAS_URLPARSE = True
-except BaseException:
- HAS_URLPARSE = False
+def make_dirs(path: Path, mode: int, uid: int, gid: int) -> None:
+ dirs_to_create = []
-def make_dirs(module, path, mode, uid, gid):
- dirs = [path]
- dirname = os.path.dirname(path)
- while dirname != '/':
- dirs.insert(0, dirname)
- dirname = os.path.dirname(dirname)
+ while not path.exists():
+ dirs_to_create.append(path)
+ if path.parent == path:
+ # Reached the root directory
+ break
+ path = path.parent
+
+ dirs_to_create.reverse()
- for dirname in dirs:
- if not os.path.exists(dirname):
- os.mkdir(dirname, mode)
- os.chown(dirname, uid, gid)
+ for dir_path in dirs_to_create:
+ if not dir_path.exists():
+ dir_path.mkdir(mode=mode, exist_ok=True)
+ os.chown(str(dir_path), uid, gid)
-def get_root_dirname_from_zip(module, zipfile_path):
- if not os.path.isfile(zipfile_path):
- module.fail_json(msg='File not found: %s' % zipfile_path)
+def get_root_dirname_from_zip(module: AnsibleModule, zipfile_path: Path) -> str:
+ if not zipfile_path.is_file():
+ module.fail_json(msg=f'File not found: {zipfile_path}')
with zipfile.ZipFile(zipfile_path, 'r') as z:
files = z.namelist()
- if len(files) == 0:
- module.fail_json(msg='Plugin is empty: %s' % zipfile_path)
+ if not files:
+ module.fail_json(msg=f'Plugin is empty: {zipfile_path}')
return files[0].split('/')[0]
-def extract_zip(module, output_dir, zipfile_path, uid, gid):
- if not os.path.isfile(zipfile_path):
- module.fail_json(msg='File not found: %s' % zipfile_path)
+def extract_zip(module: AnsibleModule, output_dir: Path, zipfile_path: Path, uid: int, gid: int) -> None:
+ if not zipfile_path.is_file():
+ module.fail_json(msg=f'File not found: {zipfile_path}')
with zipfile.ZipFile(zipfile_path, 'r') as z:
z.extractall(output_dir)
files = z.namelist()
+ output_dir_resolved = output_dir.resolve()
+
for file_entry in files:
- absolute_file = os.path.join(output_dir, file_entry)
- while not os.path.samefile(absolute_file, output_dir):
+ absolute_file = (output_dir / file_entry).resolve()
+ while not absolute_file.samefile(output_dir_resolved):
os.chown(absolute_file, uid, gid)
- absolute_file = os.path.normpath(
- os.path.join(absolute_file, os.pardir))
-
-
-def fetch_url(module, url, method=None, timeout=10, follow_redirects=True):
-
- if not HAS_URLPARSE:
- module.fail_json(msg='urlparse is not installed')
+ absolute_file = absolute_file.parent.resolve()
- # ensure we use proper tempdir
- old_tempdir = tempfile.tempdir
- tempfile.tempdir = module.tmpdir
- r = None
- info = dict(url=url, status=-1)
- try:
- r = open_url(url,
- method=method,
- timeout=timeout,
- follow_redirects=follow_redirects)
- # Lowercase keys, to conform to py2 behavior, so that py3 and py2 are
- # predictable
- info.update(dict((k.lower(), v) for k, v in r.info().items()))
-
- # Don't be lossy, append header values for duplicate headers
- # In Py2 there is nothing that needs done, py2 does this for us
- if PY3:
- temp_headers = {}
- for name, value in r.headers.items():
- # The same as above, lower case keys to match py2 behavior, and
- # create more consistent results
- name = name.lower()
- if name in temp_headers:
- temp_headers[name] = ', '.join((temp_headers[name], value))
- else:
- temp_headers[name] = value
- info.update(temp_headers)
-
- # finally update the result with a message about the fetch
- info.update(
- dict(msg='OK (%s bytes)' %
- r.headers.get('Content-Length', 'unknown'),
- url=r.geturl(),
- status=r.code))
- except NoSSLError as e:
- distribution = get_distribution()
- if distribution is not None and distribution.lower() == 'redhat':
- module.fail_json(
- msg='%s. You can also install python-ssl from EPEL' %
- to_native(e), **info)
- else:
- module.fail_json(msg='%s' % to_native(e), **info)
- except (ConnectionError, ValueError) as e:
- module.fail_json(msg=to_native(e), **info)
- except urllib_error.HTTPError as e:
- try:
- body = e.read()
- except AttributeError:
- body = ''
-
- # Try to add exception info to the output but don't fail if we can't
- try:
- # Lowercase keys, to conform to py2 behavior, so that py3 and py2
- # are predictable
- info.update(dict((k.lower(), v) for k, v in e.info().items()))
- except Exception:
- pass
-
- info.update({'msg': to_native(e), 'body': body, 'status': e.code})
-
- except urllib_error.URLError as e:
- code = int(getattr(e, 'code', -1))
- info.update(dict(msg='Request failed: %s' % to_native(e), status=code))
- except socket.error as e:
- info.update(
- dict(
- msg='Connection failure: %s' %
- to_native(e),
- status=-
- 1))
- except httplib.BadStatusLine as e:
- info.update(
- dict(
- msg=('Connection failure: connection was closed before a valid'
- ' response was received: %s') %
- to_native(
- e.line),
- status=-
- 1))
- except Exception as e:
- info.update(dict(msg='An unknown error occurred: %s' % to_native(e),
- status=-1),
- exception=traceback.format_exc())
- finally:
- tempfile.tempdir = old_tempdir
-
- return r, info
-
-
-def get_build_number_from_xml(module, intellij_home, xml):
+def get_build_number_from_xml(module: AnsibleModule, intellij_home: Path, xml: Any) -> str:
info_doc = etree.parse(xml)
build = info_doc.find('./build/[@number]')
if build is None:
- build = info_doc.find(
- './{http://jetbrains.org/intellij/schema/application-info}build/'
- '[@number]'
- )
+ build = info_doc.find('./{http://jetbrains.org/intellij/schema/application-info}build/''[@number]')
if build is None:
- module.fail_json(
- msg=('Unable to determine IntelliJ version from path: %s '
- '(unsupported schema - missing build element)') %
- intellij_home)
+ module.fail_json(msg=f'Unable to determine IntelliJ version from path: {intellij_home} (unsupported schema - missing build element)')
build_number = build.get('number')
if build_number is None:
- module.fail_json(
- msg=('Unable to determine IntelliJ version from path: %s '
- '(unsupported schema - missing build number value)') %
- intellij_home)
+ module.fail_json(msg=f'Unable to determine IntelliJ version from path: {intellij_home} (unsupported schema - missing build number value)')
return build_number
-def get_build_number_from_jar(module, intellij_home):
- resources_jar = os.path.join(intellij_home, 'lib', 'resources.jar')
+def get_build_number_from_jar(module: AnsibleModule, intellij_home: Path) -> Optional[str]:
+ resources_jar = intellij_home / 'lib' / 'resources.jar'
- if not os.path.isfile(resources_jar):
+ if not resources_jar.is_file():
return None
with zipfile.ZipFile(resources_jar, 'r') as resource_zip:
@@ -278,76 +157,59 @@ def get_build_number_from_jar(module, intellij_home):
except KeyError:
try:
with resource_zip.open('idea/ApplicationInfo.xml') as xml:
- return get_build_number_from_xml(module, intellij_home,
- xml)
+ return get_build_number_from_xml(module, intellij_home, xml)
except KeyError:
- module.fail_json(
- msg=('Unable to determine IntelliJ version from path: %s '
- '(XML info file not found in "lib/resources.jar")') %
- intellij_home)
+ module.fail_json(msg=f'Unable to determine IntelliJ version from path: {intellij_home} (XML info file not found in "lib/resources.jar")')
-def get_build_number_from_json(module, intellij_home):
- product_info_path = os.path.join(intellij_home, 'product-info.json')
+def get_build_number_from_json(module: AnsibleModule, intellij_home: Path) -> str:
+ product_info_path = intellij_home / 'product-info.json'
- if not os.path.isfile(product_info_path):
- module.fail_json(
- msg=('Unable to determine IntelliJ version from path: %s '
- '("product-info.json" not found)') %
- intellij_home)
+ if not product_info_path.is_file():
+ module.fail_json(msg=f'Unable to determine IntelliJ version from path: {intellij_home} ("product-info.json" not found)')
- with open(product_info_path) as product_info_file:
+ with product_info_path.open() as product_info_file:
product_info = json.load(product_info_file)
return product_info['buildNumber']
-def get_build_number(module, intellij_home):
- return get_build_number_from_jar(
- module, intellij_home) or get_build_number_from_json(
- module, intellij_home)
-
+def get_build_number(module: AnsibleModule, intellij_home: Path) -> str:
+ return get_build_number_from_jar(module, intellij_home) or get_build_number_from_json(module, intellij_home)
-def get_plugin_info(module, plugin_manager_url, intellij_home, plugin_id):
+def get_plugin_info(module: AnsibleModule, plugin_manager_url: str, intellij_home: Path, plugin_id: str) -> Tuple[str, str]:
build_number = get_build_number(module, intellij_home)
params = {'action': 'download', 'build': build_number, 'id': plugin_id}
- query_params = urlencode(params)
+ query_params = urllib.parse.urlencode(params)
- url = '%s?%s' % (plugin_manager_url, query_params)
- for _ in range(0, 3):
- resp, info = fetch_url(module,
- url,
- method='HEAD',
- timeout=3,
- follow_redirects=False)
- if resp is not None:
+ url = f'{plugin_manager_url}?{query_params}'
+
+ for _ in range(3):
+ module.params['follow_redirects'] = 'none'
+ resp, info = fetch_url(module, url, method='HEAD', timeout=3)
+ if resp:
resp.close()
- status_code = info['status']
+ status_code = info.get('status', -1)
if status_code == 404:
- module.fail_json(msg='Unable to find plugin "%s" for build "%s"' %
- (plugin_id, build_number))
- if status_code > -1 and status_code < 400:
+ module.fail_json(msg=f'Unable to find plugin "{plugin_id}" for build "{build_number}"')
+ if 0 <= status_code < 400:
break
- # 3 retries 5 seconds appart
+ # 3 retries 5 seconds apart
time.sleep(5)
if status_code == -1 or status_code >= 400:
- module.fail_json(msg='Error querying url "%s": %s' %
- (url, info['msg']))
+ module.fail_json(msg=f'Error querying url "{url}": {info.get("msg", "Unknown error")}')
- location = info.get('location')
- if location is None:
- location = info.get('Location')
- if location is None:
- module.fail_json(msg='Unsupported HTTP response for: %s (status=%s)' %
- (url, status_code))
+ location = info.get('location') or info.get('Location')
+ if not location:
+ module.fail_json(msg=f'Unsupported HTTP response for: {url} (status={status_code})')
if location.startswith('http'):
plugin_url = location
else:
- plugin_url = urljoin(plugin_manager_url, location)
+ plugin_url = urllib.parse.urljoin(plugin_manager_url, location)
jar_pattern = re.compile(r'/(?P[^/]+\.jar)(?:\?.*)$')
jar_matcher = jar_pattern.search(plugin_url)
@@ -355,95 +217,90 @@ def get_plugin_info(module, plugin_manager_url, intellij_home, plugin_id):
if jar_matcher:
file_name = jar_matcher.group('file_name')
else:
- versioned_pattern = re.compile(
- r'(?P[0-9]+)/(?P[0-9]+)/'
- r'(?P[^/]+)(?:\?.*)$'
- )
+ versioned_pattern = re.compile(r'(?P[0-9]+)/(?P[0-9]+)/(?P[^/]+)(?:\?.*)$')
versioned_matcher = versioned_pattern.search(plugin_url)
if versioned_matcher:
- file_name = '%s-%s-%s' % (versioned_matcher.group('plugin_id'),
- versioned_matcher.group('update_id'),
- versioned_matcher.group('file_name'))
+ plugin_id = versioned_matcher.group('plugin_id')
+ update_id = versioned_matcher.group('update_id')
+ file_name = versioned_matcher.group('file_name')
+ file_name = f'{plugin_id}-{update_id}-{file_name}'
else:
- hash_object = hashlib.sha256(plugin_url)
- file_name = '%s-%s.zip' % (plugin_id, hash_object.hexdigest())
+ hash_object = hashlib.sha256(plugin_url.encode())
+ file_name = f'{plugin_id}-{hash_object.hexdigest()}.zip'
return plugin_url, file_name
-def download_plugin(module, plugin_url, file_name, download_cache):
- if not os.path.isdir(download_cache):
- os.makedirs(download_cache, 0o775)
+def download_plugin(module: AnsibleModule, plugin_url: str, file_name: str, download_cache: Path) -> Path:
+ if not download_cache.is_dir():
+ download_cache.mkdir(mode=0o775, parents=True)
- download_path = os.path.join(download_cache, file_name)
+ download_path = download_cache / file_name
- if os.path.isfile(download_path):
+ if download_path.is_file():
return download_path
- for _ in range(0, 3):
- resp, info = fetch_url(module,
- plugin_url,
- method='GET',
- timeout=20,
- follow_redirects=True)
- status_code = info['status']
-
- if status_code >= 200 and status_code < 300:
- tmp_dest = getattr(module, 'tmpdir', None)
-
- fd, b_tempname = tempfile.mkstemp(dir=tmp_dest)
-
- f = os.fdopen(fd, 'wb')
- try:
- shutil.copyfileobj(resp, f)
- except Exception as e:
- os.remove(b_tempname)
+ for _ in range(3):
+ module.params['follow_redirects'] = 'all'
+ resp, info = fetch_url(module, plugin_url, method='GET', timeout=20)
+ status_code = info.get('status', -1)
+
+ if 200 <= status_code < 300:
+ tmp_dest = module.tmpdir
+
+ fd, tempname = tempfile.mkstemp(dir=tmp_dest)
+
+ with os.fdopen(fd, 'wb') as f:
+ try:
+ shutil.copyfileobj(resp, f)
+ except Exception as e:
+ os.remove(tempname)
+ if resp:
+ resp.close()
+ module.fail_json(msg=f'Failed to create temporary content file: {e}')
+ if resp:
resp.close()
- module.fail_json(
- msg='Failed to create temporary content file: %s' %
- to_native(e))
- f.close()
- resp.close()
-
- module.atomic_move(to_native(b_tempname), download_path)
-
+ module.atomic_move(tempname, str(download_path))
return download_path
- if resp is not None:
+ if resp:
resp.close()
- module.fail_json(msg='Error downloading url "%s": %s' %
- (plugin_url, info['msg']))
+ module.fail_json(msg=f'Error downloading url "{plugin_url}": {info["msg"]}')
-def install_plugin(module, plugin_manager_url, intellij_home, plugins_dir, uid,
- gid, plugin_id, download_cache):
- plugin_url, file_name = get_plugin_info(module, plugin_manager_url,
- intellij_home, plugin_id)
+def install_plugin(
+ module: AnsibleModule,
+ plugin_manager_url: str,
+ intellij_home: Path,
+ plugins_dir: Path,
+ uid: int,
+ gid: int,
+ plugin_id: str,
+ download_cache: Path) -> bool:
+ plugin_url, file_name = get_plugin_info(module, plugin_manager_url, intellij_home, plugin_id)
- plugin_path = download_plugin(module, plugin_url, file_name,
- download_cache)
+ plugin_path = download_plugin(module, plugin_url, file_name, download_cache)
if not module.check_mode:
- make_dirs(module, plugins_dir, 0o775, uid, gid)
-
- if plugin_path.endswith('.jar'):
- dest_path = os.path.join(plugins_dir, os.path.basename(plugin_path))
+ make_dirs(plugins_dir, 0o775, uid, gid)
- if os.path.exists(dest_path):
+ if plugin_path.suffix == '.jar':
+ dest_path = plugins_dir / plugin_path.name
+ if dest_path.exists():
return False
if not module.check_mode:
shutil.copy(plugin_path, dest_path)
os.chown(dest_path, uid, gid)
- os.chmod(dest_path, 0o664)
+ dest_path.chmod(0o664)
return True
else:
root_dirname = get_root_dirname_from_zip(module, plugin_path)
- plugin_dir = os.path.join(plugins_dir, root_dirname)
+ plugin_dir = plugins_dir / root_dirname
- if os.path.exists(plugin_dir):
+ if plugin_dir.exists():
return False
if not module.check_mode:
@@ -451,21 +308,22 @@ def install_plugin(module, plugin_manager_url, intellij_home, plugins_dir, uid,
return True
-def run_module():
+def run_module() -> None:
- module_args = dict(plugin_manager_url=dict(type='str', required=True),
- intellij_home=dict(type='path', required=True),
- intellij_user_plugins_dir=dict(type='path',
- required=True),
- owner=dict(type='str', required=True),
- group=dict(type='str', required=True),
- plugin_id=dict(type='str', required=True),
- download_cache=dict(type='path', required=True))
+ module_args = dict(
+ plugin_manager_url=dict(type='str', required=True),
+ intellij_home=dict(type='path', required=True),
+ intellij_user_plugins_dir=dict(type='path', required=True),
+ owner=dict(type='str', required=True),
+ group=dict(type='str', required=True),
+ plugin_id=dict(type='str', required=True),
+ download_cache=dict(type='path', required=True)
+ )
module = AnsibleModule(argument_spec=module_args, supports_check_mode=True)
plugin_manager_url = module.params['plugin_manager_url']
- intellij_home = os.path.expanduser(module.params['intellij_home'])
+ intellij_home = Path(os.path.expanduser(module.params['intellij_home']))
owner = module.params['owner']
group = module.params['group']
@@ -480,42 +338,31 @@ def run_module():
except ValueError:
gid = grp.getgrnam(group).gr_gid
- intellij_user_plugins_dir = os.path.expanduser(
- os.path.join('~' + username,
- module.params['intellij_user_plugins_dir']))
+ intellij_user_plugins_dir = (Path('~' + username) / module.params['intellij_user_plugins_dir']).expanduser()
plugin_id = module.params['plugin_id']
- download_cache = os.path.expanduser(module.params['download_cache'])
+ download_cache = Path(module.params['download_cache']).expanduser()
# Check if we have lxml 2.3.0 or newer installed
if not HAS_LXML:
- module.fail_json(
- msg='The xml ansible module requires the lxml python library '
- 'installed on the managed machine')
- elif LooseVersion('.'.join(
- to_native(f) for f in etree.LXML_VERSION)) < LooseVersion('2.3.0'):
- module.fail_json(
- msg='The xml ansible module requires lxml 2.3.0 or newer '
- 'installed on the managed machine')
- elif LooseVersion('.'.join(
- to_native(f) for f in etree.LXML_VERSION)) < LooseVersion('3.0.0'):
- module.warn(
- 'Using lxml version lower than 3.0.0 does not guarantee '
- 'predictable element attribute order.'
- )
-
- changed = install_plugin(module, plugin_manager_url, intellij_home,
- intellij_user_plugins_dir, uid, gid, plugin_id,
- download_cache)
+ module.fail_json(msg='The xml ansible module requires the lxml python library installed on the managed machine')
+ else:
+ lxml_version = LooseVersion('.'.join(str(f) for f in etree.LXML_VERSION))
+ if lxml_version < LooseVersion('2.3.0'):
+ module.fail_json(msg='The xml ansible module requires lxml 2.3.0 or newer installed on the managed machine')
+ elif lxml_version < LooseVersion('3.0.0'):
+ module.warn('Using lxml version lower than 3.0.0 does not guarantee predictable element attribute order.')
+
+ changed = install_plugin(module, plugin_manager_url, intellij_home, intellij_user_plugins_dir, uid, gid, plugin_id, download_cache)
if changed:
- msg = 'Plugin %s has been installed' % username
+ msg = f'Plugin "{plugin_id}" has been installed'
else:
- msg = 'Plugin %s was already installed' % username
+ msg = f'Plugin "{plugin_id}" was already installed'
module.exit_json(changed=changed, msg=msg)
-def main():
+def main() -> None:
run_module()
diff --git a/library/intellij_set_default_inspection_profile.py b/library/intellij_set_default_inspection_profile.py
index fbb3701..bb19497 100644
--- a/library/intellij_set_default_inspection_profile.py
+++ b/library/intellij_set_default_inspection_profile.py
@@ -1,20 +1,13 @@
-#!/usr/bin/python
+#!/usr/bin/env python3
-# Make coding more python3-ish
-from __future__ import (absolute_import, division, print_function)
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils._text import to_bytes, to_native
-from distutils.version import LooseVersion
-import pwd
import grp
import os
-__metaclass__ = type
+import pwd
+from pathlib import Path
+from typing import Dict, Tuple
-ANSIBLE_METADATA = {
- 'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'community'
-}
+from ansible.module_utils.basic import AnsibleModule
+from ansible.module_utils.compat.version import LooseVersion
DOCUMENTATION = '''
---
@@ -70,124 +63,122 @@
HAS_LXML = False
-def pretty_print(elem):
- text = etree.tostring(elem, encoding='iso-8859-1')
+def pretty_print(elem: etree.Element) -> str:
+ text = etree.tostring(elem, encoding='unicode')
parser = etree.XMLParser(remove_blank_text=True)
xml = etree.fromstring(text, parser)
- return etree.tostring(xml,
- encoding='iso-8859-1',
- pretty_print=True,
- xml_declaration=False)
+ return etree.tostring(xml, encoding='unicode', pretty_print=True, xml_declaration=False)
-def set_option(elem, key, value):
- option = elem.find('./option[@name="%s"]' % key)
+def set_option(elem: etree.Element, key: str, value: str) -> bool:
+ option = elem.find(f'./option[@name="{key}"]')
if option is None:
option = etree.SubElement(elem, 'option', name=key)
- if option.attrib.get('value', None) == value:
+ if option.attrib.get('value') == value:
return False
option.set('value', value)
return True
-def set_version(elem, value):
+def set_version(elem: etree.Element, value: str) -> bool:
version = elem.find('./version')
if version is None:
version = etree.SubElement(elem, 'version', value=value)
- if version.attrib.get('value', None) == value:
+ if version.attrib.get('value') == value:
return False
version.set('value', value)
return True
-def make_dirs(path, mode, uid, gid):
- dirs = [path]
- dirname = os.path.dirname(path)
- while dirname != '/':
- dirs.insert(0, dirname)
- dirname = os.path.dirname(dirname)
+def make_dirs(path: Path, mode: int, uid: int, gid: int) -> None:
+ dirs_to_create = []
- for dirname in dirs:
- if not os.path.exists(dirname):
- os.mkdir(dirname, mode)
- os.chown(dirname, uid, gid)
+ while not path.exists():
+ dirs_to_create.append(path)
+ if path.parent == path:
+ # Reached the root directory
+ break
+ path = path.parent
+ dirs_to_create.reverse()
-def set_default_inspection_profile(module, intellij_user_config_dir,
- profile_name, uid, gid):
- options_dir = os.path.join(intellij_user_config_dir, 'options')
+ for dir_path in dirs_to_create:
+ if not dir_path.exists():
+ dir_path.mkdir(mode=mode, exist_ok=True)
+ os.chown(str(dir_path), uid, gid)
- project_default_path = os.path.join(options_dir, 'project.default.xml')
- create_project_default = (not os.path.isfile(project_default_path)
- ) or os.path.getsize(project_default_path) == 0
+def set_default_inspection_profile(
+ module: AnsibleModule,
+ intellij_user_config_dir: Path,
+ profile_name: str,
+ uid: int,
+ gid: int
+) -> Tuple[bool, Dict[str, str]]:
+ options_dir = intellij_user_config_dir / 'options'
+ project_default_path = options_dir / 'project.default.xml'
+
+ create_project_default = (
+ not project_default_path.is_file()
+ or project_default_path.stat().st_size == 0
+ )
if create_project_default:
if not module.check_mode:
- if not os.path.isdir(options_dir):
+ if not options_dir.is_dir():
make_dirs(options_dir, 0o775, uid, gid)
- if not os.path.isfile(project_default_path):
- with open(project_default_path, 'wb', 0o664) as xml_file:
- xml_file.write('')
+ if not project_default_path.is_file():
+ project_default_path.touch()
os.chown(project_default_path, uid, gid)
+ project_default_path.chmod(0o664)
project_default_root = etree.Element('application')
- project_default_doc = etree.ElementTree(project_default_root)
before = ''
else:
- project_default_doc = etree.parse(project_default_path)
- project_default_root = project_default_doc.getroot()
+ project_default_root = etree.parse(str(project_default_path)).getroot()
before = pretty_print(project_default_root)
if project_default_root.tag != 'application':
- module.fail_json(msg='Unsupported root element: %s' %
- project_default_root.tag)
+ module.fail_json(msg=f'Unsupported root element: {project_default_root.tag}')
- project_manager = project_default_root.find(
- './component[@name="ProjectManager"]')
+ project_manager = project_default_root.find('./component[@name="ProjectManager"]')
if project_manager is None:
- project_manager = etree.SubElement(project_default_root,
- 'component',
- name='ProjectManager')
+ project_manager = etree.SubElement(project_default_root, 'component', name='ProjectManager')
default_project = project_manager.find('./defaultProject')
if default_project is None:
default_project = etree.SubElement(project_manager, 'defaultProject')
- profile_manager = default_project.find(
- './component[@name="InspectionProjectProfileManager"]')
+ profile_manager = default_project.find('./component[@name="InspectionProjectProfileManager"]')
if profile_manager is None:
- profile_manager = etree.SubElement(
- default_project,
- 'component',
- name='InspectionProjectProfileManager')
+ profile_manager = etree.SubElement(default_project, 'component', name='InspectionProjectProfileManager')
- changed = True in [
+ changed = any([
set_option(profile_manager, 'PROJECT_PROFILE', profile_name),
set_option(profile_manager, 'USE_PROJECT_PROFILE', 'false'),
set_version(profile_manager, '1.0')
- ]
+ ])
after = pretty_print(project_default_root)
if changed and not module.check_mode:
- with open(project_default_path, 'wb') as xml_file:
- xml_file.write(to_bytes(after))
+ project_default_path.write_text(after, encoding='iso-8859-1')
- return changed, {'before:': before, 'after': after}
+ return changed, {'before': before, 'after': after}
-def run_module():
+def run_module() -> None:
- module_args = dict(intellij_user_config_dir=dict(type='str',
- required=True),
- profile_name=dict(type='str', required=True),
- owner=dict(type='str', required=True),
- group=dict(type='str', required=True))
+ module_args = dict(
+ intellij_user_config_dir=dict(type='str', required=True),
+ profile_name=dict(type='str', required=True),
+ owner=dict(type='str', required=True),
+ group=dict(type='str', required=True)
+ )
module = AnsibleModule(argument_spec=module_args, supports_check_mode=True)
@@ -205,41 +196,30 @@ def run_module():
except ValueError:
gid = grp.getgrnam(group).gr_gid
- intellij_user_config_dir = os.path.expanduser(
- os.path.join('~' + username,
- module.params['intellij_user_config_dir']))
- profile_name = os.path.expanduser(module.params['profile_name'])
+ intellij_user_config_dir = Path(f'~{username}', module.params['intellij_user_config_dir']).expanduser()
+ profile_name = module.params['profile_name']
# Check if we have lxml 2.3.0 or newer installed
if not HAS_LXML:
- module.fail_json(
- msg='The xml ansible module requires the lxml python library '
- 'installed on the managed machine')
- elif LooseVersion('.'.join(
- to_native(f) for f in etree.LXML_VERSION)) < LooseVersion('2.3.0'):
- module.fail_json(
- msg='The xml ansible module requires lxml 2.3.0 or newer '
- 'installed on the managed machine')
- elif LooseVersion('.'.join(
- to_native(f) for f in etree.LXML_VERSION)) < LooseVersion('3.0.0'):
- module.warn(
- 'Using lxml version lower than 3.0.0 does not guarantee '
- 'predictable element attribute order.'
- )
-
- changed, diff = set_default_inspection_profile(module,
- intellij_user_config_dir,
- profile_name, uid, gid)
+ module.fail_json(msg='The xml ansible module requires the lxml python library installed on the managed machine')
+ else:
+ lxml_version = LooseVersion('.'.join(str(f) for f in etree.LXML_VERSION))
+ if lxml_version < LooseVersion('2.3.0'):
+ module.fail_json(msg='The xml ansible module requires lxml 2.3.0 or newer installed on the managed machine')
+ elif lxml_version < LooseVersion('3.0.0'):
+ module.warn('Using lxml version lower than 3.0.0 does not guarantee predictable element attribute order.')
+
+ changed, diff = set_default_inspection_profile(module, intellij_user_config_dir, profile_name, uid, gid)
if changed:
- msg = '%s is now the default inspection profile' % profile_name
+ msg = f'{profile_name} is now the default inspection profile'
else:
- msg = '%s is already the default inspection profile' % profile_name
+ msg = f'{profile_name} is already the default inspection profile'
module.exit_json(changed=changed, msg=msg, diff=diff)
-def main():
+def main() -> None:
run_module()
diff --git a/library/intellij_set_default_jdk.py b/library/intellij_set_default_jdk.py
index ab32f9d..9a754ed 100644
--- a/library/intellij_set_default_jdk.py
+++ b/library/intellij_set_default_jdk.py
@@ -1,22 +1,14 @@
-#!/usr/bin/python
+#!/usr/bin/env python3
-# Make coding more python3-ish
-from __future__ import (absolute_import, division, print_function)
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils._text import to_bytes, to_native
-from distutils.version import LooseVersion
-import tempfile
-import shutil
-import pwd
import grp
import os
-__metaclass__ = type
+import pwd
+import tempfile
+from pathlib import Path
+from typing import Any, Dict, Tuple
-ANSIBLE_METADATA = {
- 'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'community'
-}
+from ansible.module_utils.basic import AnsibleModule
+from ansible.module_utils.compat.version import LooseVersion
DOCUMENTATION = '''
---
@@ -69,184 +61,157 @@
HAS_LXML = False
-def pretty_print(elem):
- text = etree.tostring(elem, encoding='iso-8859-1')
+def pretty_print(elem: etree.Element) -> str:
+ text = etree.tostring(elem, encoding='unicode')
parser = etree.XMLParser(remove_blank_text=True)
xml = etree.fromstring(text, parser)
- return etree.tostring(xml,
- encoding='iso-8859-1',
- pretty_print=True,
- xml_declaration=False)
+ return etree.tostring(xml, encoding='unicode', pretty_print=True, xml_declaration=False)
-def set_attrib(elem, key, value):
- if elem.attrib.get(key, None) == value:
+def set_attrib(elem: etree.Element, key: str, value: str) -> bool:
+ if elem.attrib.get(key) == value:
return False
elem.set(key, value)
return True
-def jdk_home(module, intellij_user_config_dir, jdk_name):
- jdk_table_path = os.path.join(intellij_user_config_dir, 'options',
- 'jdk.table.xml')
- if not os.path.isfile(jdk_table_path):
- module.fail_json(msg='File not found: %s' % jdk_table_path)
+def jdk_home(module: AnsibleModule, intellij_user_config_dir: Path, jdk_name: str) -> Path:
+ jdk_table_path = intellij_user_config_dir / 'options' / 'jdk.table.xml'
+ if not jdk_table_path.is_file():
+ module.fail_json(msg=f'File not found: {jdk_table_path}')
- jdk_table_doc = etree.parse(jdk_table_path)
-
- jdk = jdk_table_doc.find(
- './component[@name="ProjectJdkTable"]/jdk/name[@value="%s"]/..' %
- jdk_name)
+ jdk_table_doc = etree.parse(str(jdk_table_path))
+ jdk = jdk_table_doc.find(f'./component[@name="ProjectJdkTable"]/jdk/name[@value="{jdk_name}"]/..')
if jdk is None:
- module.fail_json(
- msg='Unable to find JDK with name "%s" in jdk.table.xml' %
- jdk_name)
+ module.fail_json(msg=f'Unable to find JDK with name "{jdk_name}" in jdk.table.xml')
path_node = jdk.find('./homePath')
if path_node is None:
- module.fail_json(msg='Invalid XML: homePath missing for JDK: %s' %
- jdk_name)
+ module.fail_json(msg=f'Invalid XML: homePath missing for JDK: {jdk_name}')
- path = path_node.attrib.get('value', None)
+ path = path_node.attrib.get('value')
if path is None:
- module.fail_json(
- msg='Invalid XML: homePath/@value missing for JDK: %s' % jdk_name)
+ module.fail_json(msg=f'Invalid XML: homePath/@value missing for JDK: {jdk_name}')
- return path
+ return Path(path)
-def specification_version(module, jdk_home):
+def specification_version(module: AnsibleModule, jdk_home: Path) -> str:
+ javac = jdk_home / 'bin' / 'javac'
+ if not javac.is_file():
+ module.fail_json(msg=f'File not found: {javac}')
- dirpath = tempfile.mkdtemp()
- try:
- src_file = os.path.join(dirpath, 'SpecificationVersion.java')
- with open(src_file, 'w') as java_file:
- java_file.write('''
+ java = jdk_home / 'bin' / 'java'
+ if not java.is_file():
+ module.fail_json(msg=f'File not found: {java}')
+
+ with tempfile.TemporaryDirectory() as dirpath:
+ dirpath = Path(dirpath)
+ src_file = dirpath / 'SpecificationVersion.java'
+ src_file.write_text('''
public class SpecificationVersion {
public static void main(String[] args) {
System.out.print(System.getProperty("java.specification.version"));
}
}
''')
-
- javac = os.path.join(jdk_home, 'bin', 'javac')
- if not os.path.isfile(javac):
- module.fail_json(msg='File not found: %s' % javac)
-
- rc, out, err = module.run_command([javac, 'SpecificationVersion.java'],
- cwd=dirpath)
+ rc, out, err = module.run_command([str(javac), 'SpecificationVersion.java'], cwd=str(dirpath))
if rc != 0 or err:
- module.fail_json(
- msg='Error while querying Java specification version: %s' %
- (out + err))
+ module.fail_json(msg=f'Error while querying Java specification version: {out}{err}')
- java = os.path.join(jdk_home, 'bin', 'java')
- if not os.path.isfile(java):
- module.fail_json(msg='File not found: %s' % java)
-
- rc, out, err = module.run_command([java, 'SpecificationVersion'],
- cwd=dirpath)
+ rc, out, err = module.run_command([str(java), 'SpecificationVersion'], cwd=str(dirpath))
if rc != 0 or err:
- module.fail_json(
- msg='Error while querying Java specification version: %s' %
- (out + err))
+ module.fail_json(msg=f'Error while querying Java specification version: {out}{err}')
return out.strip()
- finally:
- shutil.rmtree(dirpath)
-def make_dirs(path, mode, uid, gid):
- dirs = [path]
- dirname = os.path.dirname(path)
- while dirname != '/':
- dirs.insert(0, dirname)
- dirname = os.path.dirname(dirname)
+def make_dirs(path: Path, mode: int, uid: int, gid: int) -> None:
+ dirs_to_create = []
+
+ while not path.exists():
+ dirs_to_create.append(path)
+ if path.parent == path:
+ # Reached the root directory
+ break
+ path = path.parent
- for dirname in dirs:
- if not os.path.exists(dirname):
- os.mkdir(dirname, mode)
- os.chown(dirname, uid, gid)
+ dirs_to_create.reverse()
+ for dir_path in dirs_to_create:
+ if not dir_path.exists():
+ dir_path.mkdir(mode=mode, exist_ok=True)
+ os.chown(str(dir_path), uid, gid)
-def set_default_jdk(module, intellij_user_config_dir, jdk_name, uid, gid):
- options_dir = os.path.join(intellij_user_config_dir, 'options')
- project_default_path = os.path.join(options_dir, 'project.default.xml')
+def set_default_jdk(module: AnsibleModule, intellij_user_config_dir: Path, jdk_name: str, uid: int, gid: int) -> Tuple[bool, Dict[str, Any]]:
+ options_dir = intellij_user_config_dir / 'options'
+ project_default_path = options_dir / 'project.default.xml'
+
+ create_project_default = not project_default_path.is_file() or project_default_path.stat().st_size == 0
- create_project_default = (not os.path.isfile(project_default_path)
- ) or os.path.getsize(project_default_path) == 0
if create_project_default:
if not module.check_mode:
- if not os.path.isdir(options_dir):
+ if not options_dir.is_dir():
make_dirs(options_dir, 0o775, uid, gid)
- if not os.path.isfile(project_default_path):
- with open(project_default_path, 'wb', 0o664) as xml_file:
- xml_file.write(to_bytes(''))
- os.chown(project_default_path, uid, gid)
+ if not project_default_path.is_file():
+ project_default_path.touch()
+ project_default_path.chmod(project_default_path, 0o664)
+ os.chown(str(project_default_path), uid, gid)
project_default_root = etree.Element('application')
- project_default_doc = etree.ElementTree(project_default_root)
before = ''
else:
- project_default_doc = etree.parse(project_default_path)
+ project_default_doc = etree.parse(str(project_default_path))
project_default_root = project_default_doc.getroot()
before = pretty_print(project_default_root)
if project_default_root.tag != 'application':
- module.fail_json(msg='Unsupported root element: %s' %
- project_default_root.tag)
+ module.fail_json(msg=f'Unsupported root element: {project_default_root.tag}')
- project_manager = project_default_root.find(
- './component[@name="ProjectManager"]')
+ project_manager = project_default_root.find('./component[@name="ProjectManager"]')
if project_manager is None:
- project_manager = etree.SubElement(project_default_root,
- 'component',
- name='ProjectManager')
+ project_manager = etree.SubElement(project_default_root, 'component', name='ProjectManager')
default_project = project_manager.find('./defaultProject')
if default_project is None:
default_project = etree.SubElement(project_manager, 'defaultProject')
- project_root_manager = default_project.find(
- './component[@name="ProjectRootManager"]')
+ project_root_manager = default_project.find('./component[@name="ProjectRootManager"]')
if project_root_manager is None:
- project_root_manager = etree.SubElement(default_project,
- 'component',
- name='ProjectRootManager')
+ project_root_manager = etree.SubElement(default_project, 'component', name='ProjectRootManager')
default_jdk_home = jdk_home(module, intellij_user_config_dir, jdk_name)
language_level = specification_version(module, default_jdk_home)
- changed = True in [
+ changed = any([
set_attrib(project_root_manager, 'version', '2'),
- set_attrib(project_root_manager, 'languageLevel',
- 'JDK_%s' % language_level.replace('.', '_')),
+ set_attrib(project_root_manager, 'languageLevel', f'JDK_{language_level.replace(".", "_")}'),
set_attrib(project_root_manager, 'default', 'true'),
set_attrib(project_root_manager, 'assert-keyword', 'true'),
set_attrib(project_root_manager, 'jdk-15', 'true'),
set_attrib(project_root_manager, 'project-jdk-name', jdk_name),
set_attrib(project_root_manager, 'project-jdk-type', 'JavaSDK')
- ]
+ ])
after = pretty_print(project_default_root)
if changed and not module.check_mode:
- with open(project_default_path, 'wb') as xml_file:
- xml_file.write(to_bytes(after))
-
- return changed, {'before:': before, 'after': after}
+ project_default_path.write_text(after, encoding='iso-8859-1')
+ os.chown(str(project_default_path), uid, gid)
+ return changed, {'before': before, 'after': after}
-def run_module():
- module_args = dict(intellij_user_config_dir=dict(type='str',
- required=True),
- jdk_name=dict(type='str', required=True),
- owner=dict(type='str', required=True),
- group=dict(type='str', required=True))
+def run_module() -> None:
+ module_args = dict(
+ intellij_user_config_dir=dict(type='str', required=True),
+ jdk_name=dict(type='str', required=True),
+ owner=dict(type='str', required=True),
+ group=dict(type='str', required=True)
+ )
module = AnsibleModule(argument_spec=module_args, supports_check_mode=True)
@@ -264,40 +229,30 @@ def run_module():
except ValueError:
gid = grp.getgrnam(group).gr_gid
- intellij_user_config_dir = os.path.expanduser(
- os.path.join('~' + username,
- module.params['intellij_user_config_dir']))
- jdk_name = os.path.expanduser(module.params['jdk_name'])
+ intellij_user_config_dir = Path(f'~{username}', module.params['intellij_user_config_dir']).expanduser()
+ jdk_name = module.params['jdk_name']
# Check if we have lxml 2.3.0 or newer installed
if not HAS_LXML:
- module.fail_json(
- msg='The xml ansible module requires the lxml python library '
- 'installed on the managed machine')
- elif LooseVersion('.'.join(
- to_native(f) for f in etree.LXML_VERSION)) < LooseVersion('2.3.0'):
- module.fail_json(
- msg='The xml ansible module requires lxml 2.3.0 or newer '
- 'installed on the managed machine')
- elif LooseVersion('.'.join(
- to_native(f) for f in etree.LXML_VERSION)) < LooseVersion('3.0.0'):
- module.warn(
- 'Using lxml version lower than 3.0.0 does not guarantee '
- 'predictable element attribute order.'
- )
-
- changed, diff = set_default_jdk(module, intellij_user_config_dir, jdk_name,
- uid, gid)
+ module.fail_json(msg='The xml ansible module requires the lxml python library installed on the managed machine')
+ else:
+ lxml_version = LooseVersion('.'.join(str(f) for f in etree.LXML_VERSION))
+ if lxml_version < LooseVersion('2.3.0'):
+ module.fail_json(msg='The xml ansible module requires lxml 2.3.0 or newer installed on the managed machine')
+ elif lxml_version < LooseVersion('3.0.0'):
+ module.warn('Using lxml version lower than 3.0.0 does not guarantee predictable element attribute order.')
+
+ changed, diff = set_default_jdk(module, intellij_user_config_dir, jdk_name, uid, gid)
if changed:
- msg = '%s is now the default JDK' % jdk_name
+ msg = f'{jdk_name} is now the default JDK'
else:
- msg = '%s is already the default JDK' % jdk_name
+ msg = f'{jdk_name} is already the default JDK'
module.exit_json(changed=changed, msg=msg, diff=diff)
-def main():
+def main() -> None:
run_module()
diff --git a/library/intellij_set_default_maven.py b/library/intellij_set_default_maven.py
index 2ac43e8..6751a7f 100644
--- a/library/intellij_set_default_maven.py
+++ b/library/intellij_set_default_maven.py
@@ -1,20 +1,13 @@
-#!/usr/bin/python
+#!/usr/bin/env python3
-# Make coding more python3-ish
-from __future__ import (absolute_import, division, print_function)
-from ansible.module_utils.basic import AnsibleModule
-from ansible.module_utils._text import to_bytes, to_native
-from distutils.version import LooseVersion
-import pwd
import grp
import os
-__metaclass__ = type
+import pwd
+from pathlib import Path
+from typing import Dict, Tuple
-ANSIBLE_METADATA = {
- 'metadata_version': '1.1',
- 'status': ['preview'],
- 'supported_by': 'community'
-}
+from ansible.module_utils.basic import AnsibleModule
+from ansible.module_utils.compat.version import LooseVersion
DOCUMENTATION = '''
---
@@ -68,17 +61,14 @@
HAS_LXML = False
-def pretty_print(elem):
- text = etree.tostring(elem, encoding='iso-8859-1')
+def pretty_print(elem: etree.Element) -> str:
+ text = etree.tostring(elem, encoding='unicode')
parser = etree.XMLParser(remove_blank_text=True)
xml = etree.fromstring(text, parser)
- return etree.tostring(xml,
- encoding='iso-8859-1',
- pretty_print=True,
- xml_declaration=False)
+ return etree.tostring(xml, encoding='unicode', pretty_print=True, xml_declaration=False)
-def set_attrib(elem, key, value):
+def set_attrib(elem: etree.Element, key: str, value: str) -> bool:
if elem.attrib.get(key, None) == value:
return False
@@ -86,103 +76,93 @@ def set_attrib(elem, key, value):
return True
-def make_dirs(path, mode, uid, gid):
- dirs = [path]
- dirname = os.path.dirname(path)
- while dirname != '/':
- dirs.insert(0, dirname)
- dirname = os.path.dirname(dirname)
+def make_dirs(path: Path, mode: int, uid: int, gid: int) -> None:
+ dirs_to_create = []
+
+ while not path.exists():
+ dirs_to_create.append(path)
+ if path.parent == path:
+ # Reached the root directory
+ break
+ path = path.parent
- for dirname in dirs:
- if not os.path.exists(dirname):
- os.mkdir(dirname, mode)
- os.chown(dirname, uid, gid)
+ dirs_to_create.reverse()
+ for dir_path in dirs_to_create:
+ if not dir_path.exists():
+ dir_path.mkdir(mode=mode, exist_ok=True)
+ os.chown(str(dir_path), uid, gid)
-def set_default_maven(module, intellij_user_config_dir, maven_home, uid, gid):
- options_dir = os.path.join(intellij_user_config_dir, 'options')
- project_default_path = os.path.join(options_dir, 'project.default.xml')
+def set_default_maven(module: AnsibleModule, intellij_user_config_dir: Path, maven_home: Path, uid: int, gid: int) -> Tuple[bool, Dict[str, str]]:
+
+ options_dir = intellij_user_config_dir / 'options'
+ project_default_path = options_dir / 'project.default.xml'
+
+ create_project_default = (not project_default_path.is_file()) or project_default_path.stat().st_size == 0
- create_project_default = (not os.path.isfile(project_default_path)
- ) or os.path.getsize(project_default_path) == 0
if create_project_default:
if not module.check_mode:
- if not os.path.isdir(options_dir):
+ if not options_dir.is_dir():
make_dirs(options_dir, 0o775, uid, gid)
- if not os.path.isfile(project_default_path):
- with open(project_default_path, 'wb', 0o664) as xml_file:
- xml_file.write(to_bytes(''))
- os.chown(project_default_path, uid, gid)
+ if not project_default_path.is_file():
+ project_default_path.touch(mode=0o664)
+ os.chown(str(project_default_path), uid, gid)
project_default_root = etree.Element('application')
project_default_doc = etree.ElementTree(project_default_root)
before = ''
else:
- project_default_doc = etree.parse(project_default_path)
+ project_default_doc = etree.parse(str(project_default_path))
project_default_root = project_default_doc.getroot()
before = pretty_print(project_default_root)
if project_default_root.tag != 'application':
- module.fail_json(msg='Unsupported root element: %s' %
- project_default_root.tag)
+ module.fail_json(msg=f'Unsupported root element: {project_default_root.tag}')
- project_manager = project_default_root.find(
- './component[@name="ProjectManager"]')
+ project_manager = project_default_root.find('./component[@name="ProjectManager"]')
if project_manager is None:
- project_manager = etree.SubElement(project_default_root,
- 'component',
- name='ProjectManager')
+ project_manager = etree.SubElement(project_default_root, 'component', name='ProjectManager')
default_project = project_manager.find('./defaultProject')
if default_project is None:
default_project = etree.SubElement(project_manager, 'defaultProject')
- mvn_import_prefs = default_project.find(
- './component[@name="MavenImportPreferences"]')
+ mvn_import_prefs = default_project.find('./component[@name="MavenImportPreferences"]')
if mvn_import_prefs is None:
- mvn_import_prefs = etree.SubElement(default_project,
- 'component',
- name='MavenImportPreferences')
+ mvn_import_prefs = etree.SubElement(default_project, 'component', name='MavenImportPreferences')
- general_settings = mvn_import_prefs.find(
- './option[@name="generalSettings"]')
+ general_settings = mvn_import_prefs.find('./option[@name="generalSettings"]')
if general_settings is None:
- general_settings = etree.SubElement(mvn_import_prefs,
- 'option',
- name='generalSettings')
+ general_settings = etree.SubElement(mvn_import_prefs, 'option', name='generalSettings')
mvn_general_settings = general_settings.find('./MavenGeneralSettings')
if mvn_general_settings is None:
- mvn_general_settings = etree.SubElement(general_settings,
- 'MavenGeneralSettings')
+ mvn_general_settings = etree.SubElement(general_settings, 'MavenGeneralSettings')
mvn_home_option = mvn_general_settings.find('./option[@name="mavenHome"]')
if mvn_home_option is None:
- mvn_home_option = etree.SubElement(mvn_general_settings,
- 'option',
- name='mavenHome')
+ mvn_home_option = etree.SubElement(mvn_general_settings, 'option', name='mavenHome')
- changed = set_attrib(mvn_home_option, 'value',
- os.path.expanduser(maven_home))
+ changed = set_attrib(mvn_home_option, 'value', str(maven_home.expanduser()))
after = pretty_print(project_default_root)
if changed and not module.check_mode:
- with open(project_default_path, 'wb') as xml_file:
- xml_file.write(to_bytes(after))
+ project_default_path.write_text(after, encoding='iso-8859-1')
- return changed, {'before:': before, 'after': after}
+ return changed, {'before': before, 'after': after}
-def run_module():
+def run_module() -> None:
- module_args = dict(intellij_user_config_dir=dict(type='str',
- required=True),
- maven_home=dict(type='str', required=True),
- owner=dict(type='str', required=True),
- group=dict(type='str', required=True))
+ module_args = dict(
+ intellij_user_config_dir=dict(type='str', required=True),
+ maven_home=dict(type='str', required=True),
+ owner=dict(type='str', required=True),
+ group=dict(type='str', required=True)
+ )
module = AnsibleModule(argument_spec=module_args, supports_check_mode=True)
@@ -200,30 +180,20 @@ def run_module():
except ValueError:
gid = grp.getgrnam(group).gr_gid
- intellij_user_config_dir = os.path.expanduser(
- os.path.join('~' + username,
- module.params['intellij_user_config_dir']))
- maven_home = os.path.expanduser(module.params['maven_home'])
+ intellij_user_config_dir = Path('~' + username).expanduser() / module.params['intellij_user_config_dir']
+ maven_home = Path(module.params['maven_home']).expanduser()
# Check if we have lxml 2.3.0 or newer installed
if not HAS_LXML:
- module.fail_json(
- msg='The xml ansible module requires the lxml python library '
- 'installed on the managed machine')
- elif LooseVersion('.'.join(
- to_native(f) for f in etree.LXML_VERSION)) < LooseVersion('2.3.0'):
- module.fail_json(
- msg='The xml ansible module requires lxml 2.3.0 or newer installed'
- ' on the managed machine')
- elif LooseVersion('.'.join(
- to_native(f) for f in etree.LXML_VERSION)) < LooseVersion('3.0.0'):
- module.warn(
- 'Using lxml version lower than 3.0.0 does not guarantee '
- 'predictable element attribute order.'
- )
-
- changed, diff = set_default_maven(module, intellij_user_config_dir,
- maven_home, uid, gid)
+ module.fail_json(msg='The xml ansible module requires the lxml python library installed on the managed machine')
+ else:
+ lxml_version = LooseVersion('.'.join(str(f) for f in etree.LXML_VERSION))
+ if lxml_version < LooseVersion('2.3.0'):
+ module.fail_json(msg='The xml ansible module requires lxml 2.3.0 or newer installed on the managed machine')
+ elif lxml_version < LooseVersion('3.0.0'):
+ module.warn('Using lxml version lower than 3.0.0 does not guarantee predictable element attribute order.')
+
+ changed, diff = set_default_maven(module, intellij_user_config_dir, maven_home, uid, gid)
if changed:
msg = '%s is now the default Maven installation' % maven_home
@@ -233,7 +203,7 @@ def run_module():
module.exit_json(changed=changed, msg=msg, diff=diff)
-def main():
+def main() -> None:
run_module()
diff --git a/tasks/configure.yml b/tasks/configure.yml
index ad94c00..bffac21 100644
--- a/tasks/configure.yml
+++ b/tasks/configure.yml
@@ -1,19 +1,11 @@
# code: language=ansible
---
# Needed by custom Ansible modules
-- name: Install Python XML support (Python 2)
- become: true
- ansible.builtin.package:
- name: python-lxml
- state: present
- when: "intellij_python_major_version == '2'"
-
-- name: Install Python XML support (Python 3)
+- name: Install Python XML support
become: true
ansible.builtin.package:
name: "python3-lxml"
state: present
- when: "intellij_python_major_version == '3'"
- name: Configure license
ansible.builtin.import_tasks: configure-license.yml