Skip to content

Commit

Permalink
snap: Add custom gradle plugin
Browse files Browse the repository at this point in the history
avoid committing python cache to git
  • Loading branch information
LyzardKing committed Sep 11, 2019
1 parent a67c3fe commit ac7247b
Show file tree
Hide file tree
Showing 3 changed files with 308 additions and 4 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ status.md
# Install4J
install4j6/

# Python
__pycache__/

# Snap
parts/
stage/
Expand Down
301 changes: 301 additions & 0 deletions snap/plugins/x_gradle.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,301 @@
# -*- Mode:Python; indent-tabs-mode:nil; tab-width:4 -*-
#
# Copyright (C) 2016, 2018 Canonical Ltd
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 3 as
# published by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.

"""This plugin is useful for building parts that use gradle.
The gradle build system is commonly used to build Java projects.
The plugin requires a pom.xml in the root of the source tree.
This plugin uses the common plugin keywords as well as those for "sources".
For more information check the 'plugins' topic for the former and the
'sources' topic for the latter.
Additionally, this plugin uses the following plugin-specific keywords:
- gradle-options:
(list of strings)
Flags to pass to the build using the gradle semantics for parameters.
The 'jar' option is always passed in as the last parameter.
- gradle-output-dir:
(string; default: 'build/libs')
The output directory where the resulting jar or war files from gradle[w]
are generated.
- gradle-version:
(string)
The version of gradle you want to use to build the source artifacts.
Defaults to the current release downloadable from
https://services.gradle.org/distributions/
The entry is ignored if gradlew is found.
- gradle-version-checksum:
(string)
The checksum for gradle-version in the form of <digest-type>/<digest>.
As an example "sha512/2a803f578f341e164f6753e410413d16ab60fab...".
- gradle-openjdk-version:
(string)
openjdk version available to the base to use. If not set the latest
version available to the base will be used.
"""

import logging
import os
import urllib.parse
from glob import glob
from typing import Sequence

import snapcraft
from snapcraft import file_utils, formatting_utils
from snapcraft.internal import errors, sources

logger = logging.getLogger(__name__)


_DEFAULT_GRADLE_VERSION = "4.10.2"
_DEFAULT_GRADLE_CHECKSUM = (
"sha256/b49c6da1b2cb67a0caf6c7480630b51c70a11ca2016ff2f555eaeda863143a29"
)
_GRADLE_URL = "https://services.gradle.org/distributions/gradle-{version}-bin.zip"


class UnsupportedJDKVersionError(errors.SnapcraftError):

fmt = (
"The gradle-openjdk-version plugin property was set to {version!r}.\n"
"Valid values for the {base!r} base are: {valid_versions}."
)

def __init__(
self, *, base: str, version: str, valid_versions: Sequence[str]
) -> None:
super().__init__(
base=base,
version=version,
valid_versions=formatting_utils.humanize_list(
valid_versions, conjunction="or"
),
)


class GradlePlugin(snapcraft.BasePlugin):
@classmethod
def schema(cls):
schema = super().schema()
schema["properties"]["gradle-options"] = {
"type": "array",
"minitems": 1,
"uniqueItems": True,
"items": {"type": "string"},
"default": [],
}
schema["properties"]["gradle-output-dir"] = {
"type": "string",
"default": "build/libs",
}

schema["properties"]["gradle-version"] = {"type": "string"}

schema["properties"]["gradle-version-checksum"] = {"type": "string"}

schema["properties"]["gradle-openjdk-version"] = {
"type": "string",
"default": "",
}

schema["required"] = ["source"]

return schema

@classmethod
def get_pull_properties(cls):
# Inform Snapcraft of the properties associated with pulling. If these
# change in the YAML Snapcraft will consider the pull step dirty.
return ["gradle-version", "gradle-version-checksum", "gradle-openjdk-version"]

@classmethod
def get_build_properties(cls):
# Inform Snapcraft of the properties associated with building. If these
# change in the YAML Snapcraft will consider the build step dirty.
return super().get_build_properties() + ["gradle-options", "gradle-output-dir"]

@property
def _gradle_tar(self):
if self._gradle_tar_handle is None:
gradle_uri = _GRADLE_URL.format(version=self._gradle_version)
self._gradle_tar_handle = sources.Zip(
gradle_uri, self._gradle_dir, source_checksum=self._gradle_checksum
)
return self._gradle_tar_handle

def __init__(self, name, options, project):
super().__init__(name, options, project)

self._setup_gradle()
self._setup_base_tools(project.info.get_build_base())

def _setup_base_tools(self, base):
if base not in ("core", "core16", "core18"):
raise errors.PluginBaseError(
part_name=self.name, base=self.project.info.get_build_base()
)

if base in ("core", "core16"):
valid_versions = ["8", "9"]
elif base == "core18":
valid_versions = ["8", "11"]

version = self.options.gradle_openjdk_version
if not version:
version = valid_versions[-1]
elif version not in valid_versions:
raise UnsupportedJDKVersionError(
version=version, base=base, valid_versions=valid_versions
)

self.stage_packages.append("openjdk-{}-jre-headless".format(version))
self.build_packages.append("openjdk-{}-jdk-headless".format(version))
self.build_packages.append("ca-certificates-java")
self._java_version = version

def _using_gradlew(self) -> bool:
return os.path.isfile(os.path.join(self.sourcedir, "gradlew"))

def _setup_gradle(self):
self._gradle_tar_handle = None
self._gradle_dir = os.path.join(self.partdir, "gradle")
if self.options.gradle_version:
self._gradle_version = self.options.gradle_version
self._gradle_checksum = self.options.gradle_version_checksum
else:
self._gradle_version = _DEFAULT_GRADLE_VERSION
self._gradle_checksum = _DEFAULT_GRADLE_CHECKSUM

def pull(self):
super().pull()

if self._using_gradlew():
logger.info("Found gradlew, skipping gradle setup.")
return

os.makedirs(self._gradle_dir, exist_ok=True)
self._gradle_tar.download()

def build(self):
super().build()

if self._using_gradlew():
gradle_cmd = ["./gradlew"]
else:
self._gradle_tar.provision(self._gradle_dir, keep_zip=True)
gradle_cmd = ["gradle"]
self.run(
gradle_cmd
+ self._get_proxy_options()
+ self.options.gradle_options,
rootdir=self.builddir,
)

src = os.path.join(self.builddir, self.options.gradle_output_dir)
basedir = "jabref"
# jarfiles = glob(os.path.join(src, "*.jar"))
# warfiles = glob(os.path.join(src, "*.war"))

# if len(jarfiles) > 0:
# basedir = "jar"
# elif len(warfiles) > 0:
# basedir = "war"
# jarfiles = warfiles
# else:
# raise RuntimeError("Could not find any built jar files for part")

file_utils.link_or_copy_tree(
src,
os.path.join(self.installdir, basedir),
copy_function=lambda src, dst: file_utils.link_or_copy(
src, dst, self.installdir
),
)

self._create_symlinks()

def _create_symlinks(self):
if self.project.info.get_build_base() not in ("core18", "core16", "core"):
raise errors.PluginBaseError(
part_name=self.name, base=self.project.info.get_build_base()
)

os.makedirs(os.path.join(self.installdir, "bin"), exist_ok=True)
java_bin = glob(
os.path.join(
self.installdir,
"usr",
"lib",
"jvm",
"java-{}-openjdk-*".format(self._java_version),
"bin",
"java",
)
)[0]
os.symlink(
os.path.relpath(java_bin, os.path.join(self.installdir, "bin")),
os.path.join(self.installdir, "bin", "java"),
)

def run(self, cmd, rootdir):
super().run(cmd, cwd=rootdir, env=self._build_environment())

def _build_environment(self):
if self._using_gradlew():
return

env = os.environ.copy()
gradle_bin = os.path.join(
self._gradle_dir, "gradle-{}".format(self._gradle_version), "bin"
)
print(gradle_bin)

if env.get("PATH"):
new_path = "{}:{}".format(gradle_bin, env.get("PATH"))
else:
new_path = gradle_bin

env["PATH"] = new_path
return env

def _get_proxy_options(self):
proxy_options = []
for var in ("http", "https"):
proxy = os.environ.get("{}_proxy".format(var), False)
if proxy:
parsed_url = urllib.parse.urlparse(proxy)
proxy_options.append(
"-D{}.proxyHost={}".format(var, parsed_url.hostname)
)
if parsed_url.port:
proxy_options.append(
"-D{}.proxyPort={}".format(var, parsed_url.port)
)
if parsed_url.username:
proxy_options.append(
"-D{}.proxyUser={}".format(var, parsed_url.username)
)
if parsed_url.password:
proxy_options.append(
"-D{}.proxyPassword={}".format(var, parsed_url.password)
)
return proxy_options
8 changes: 4 additions & 4 deletions snap/snapcraft.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ architectures:

apps:
jabref:
command: desktop-launch java -jar $SNAP/jar/JabRef-$SNAP_VERSION.jar
command: desktop-launch $SNAP/jabref/bin/JabRefMain
environment:
_JAVA_OPTIONS: "-Duser.home=$SNAP_USER_DATA"
plugs:
Expand All @@ -37,15 +37,15 @@ plugs:

parts:
jabref:
plugin: gradle
plugin: x_gradle
source: .
source-type: git
stage-packages:
- openjdk-11-jre
- openjfx
- x11-utils
gradle-options: [snapJar, -xtest]
gradle-output-dir: 'build/releases'
gradle-options: [jlink, -xtest]
gradle-output-dir: 'build/image'
desktop-gnome-platform:
source: https://github.com/ubuntu/snapcraft-desktop-helpers.git
source-subdir: gtk
Expand Down

0 comments on commit ac7247b

Please sign in to comment.