Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 0 additions & 6 deletions build_defs/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,3 @@ py_binary(
srcs = ["package_meta_inf_files.py"],
python_version = "PY3",
)

py_binary(
name = "zip_plugin_files",
srcs = ["zip_plugin_files.py"],
python_version = "PY3",
)
140 changes: 0 additions & 140 deletions build_defs/build_defs.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -190,146 +190,6 @@ def api_version_txt(name, check_eap, application_info_json = None, **kwargs):
**kwargs
)

def _transition_impl(_, attr):
return {"//command_line_option:javacopt": attr.java_copts}

_java_copts_transition = transition(
implementation = _transition_impl,
inputs = [],
outputs = ["//command_line_option:javacopt"],
)

repackaged_files_data = provider()

def _repackaged_files_impl(ctx):
prefix = ctx.attr.prefix
if prefix.startswith("/"):
fail("'prefix' must be a relative path")
input_files = depset()
for target in ctx.attr.srcs:
input_files = depset(transitive = [input_files, target.files])

return [
# TODO(brendandouglas): Only valid for Bazel 0.5 onwards. Uncomment when
# 0.5 used more widely.
# DefaultInfo(files = input_files),
repackaged_files_data(
files = input_files,
prefix = prefix,
strip_prefix = ctx.attr.strip_prefix,
executable = ctx.attr.executable,
),
]

_repackaged_files = rule(
implementation = _repackaged_files_impl,
attrs = {
"srcs": attr.label_list(mandatory = True, allow_files = True, cfg = _java_copts_transition),
"prefix": attr.string(mandatory = True),
"strip_prefix": attr.string(mandatory = True),
"executable": attr.bool(mandatory = False),
"java_copts": attr.string_list(default = []),
},
)

def repackaged_files(name, srcs = [], prefix = None, strip_prefix = ".", executable = False, java_copts = [], **kwargs):
"""Assembles files together so that they can be packaged as an IntelliJ plugin.

A cut-down version of the internal 'pkgfilegroup' rule.

Args:
name: The name of this target
srcs: A list of targets which are dependencies of this rule. All output files of each of these
targets will be repackaged.
prefix: Where the package should install these files, relative to the 'plugins' directory.
strip_prefix: Which part of the input file path should be stripped prior to applying 'prefix'.
If ".", all subdirectories are stripped. If the empty string, the full package-relative path
is used. Default is "."
java_copts: Java compilation options for building the targets to package.
**kwargs: Any further arguments to be passed to the target
"""
_repackaged_files(name = name, srcs = srcs, prefix = prefix, strip_prefix = strip_prefix, executable = executable, java_copts = java_copts, **kwargs)

def _strip_external_workspace_prefix(short_path):
"""If this target is sitting in an external workspace, return the workspace-relative path."""
if short_path.startswith("../") or short_path.startswith("external/"):
return "/".join(short_path.split("/")[2:])
return short_path

def output_path(f, repackaged_files_data):
"""Returns the output path of a file, for a given set of repackaging parameters."""
prefix = repackaged_files_data.prefix
strip_prefix = repackaged_files_data.strip_prefix

short_path = _strip_external_workspace_prefix(f.short_path).strip("/")

if strip_prefix == ".":
return prefix + "/" + f.basename
if strip_prefix == "":
return prefix + "/" + short_path

strip_prefix = strip_prefix.strip("/")
old_path = short_path[:-len(f.basename)].strip("/")
if not old_path.startswith(strip_prefix):
fail("Invalid strip_prefix '%s': path actually starts with '%s'" % (strip_prefix, old_path))

stripped = old_path[len(strip_prefix):].strip("/")
if stripped == "":
return "%s/%s" % (prefix, f.basename)
return "%s/%s/%s" % (prefix, stripped, f.basename)

def _plugin_deploy_zip_impl(ctx):
zip_name = ctx.attr.zip_filename
zip_file = ctx.actions.declare_file(zip_name)

input_files = depset()
exec_path_to_zip_path = {}
for target in ctx.attr.srcs:
data = target[repackaged_files_data]
input_files = depset(transitive = [input_files, data.files])
for f in data.files.to_list():
exec_path_to_zip_path[f.path] = (output_path(f, data), data.executable)

args = []
args.extend(["--output", zip_file.path])
for exec_path, (zip_path, exec) in exec_path_to_zip_path.items():
args.extend([exec_path, zip_path, "True" if exec else "False"])
ctx.actions.run(
executable = ctx.executable._zip_plugin_files,
arguments = args,
inputs = input_files.to_list(),
outputs = [zip_file],
mnemonic = "ZipPluginFiles",
progress_message = "Creating final plugin zip archive",
)
files = depset([zip_file])
return [DefaultInfo(files = files)]

_plugin_deploy_zip = rule(
implementation = _plugin_deploy_zip_impl,
attrs = {
"srcs": attr.label_list(mandatory = True, providers = []),
"zip_filename": attr.string(mandatory = True),
"_zip_plugin_files": attr.label(
default = Label("//build_defs:zip_plugin_files"),
executable = True,
cfg = "exec",
),
},
)

def plugin_deploy_zip(name, srcs, zip_filename, **kwargs):
"""Packages up plugin files into a zip archive.

Args:
name: The name of this target
srcs: A list of targets of type 'repackaged_files', specifying the input files and relative
paths to include in the output zip archive.
zip_filename: The output zip filename.
**kwargs: Any further arguments to be passed to the target
"""
_plugin_deploy_zip(name = name, zip_filename = zip_filename, srcs = srcs, **kwargs)

def combine_visibilities(*args):
"""
Concatenates the given lists of visibilities and returns the combined list.
Expand Down
28 changes: 28 additions & 0 deletions build_defs/common.bzl
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
load("@bazel_skylib//lib:paths.bzl", "paths")

def _compute_plugin_layout(prefix, targets):
"""Computes the plugin layout from the target list.

All files of the targets are install into the lib directory, this should only be jars. Runfiles
of the targets are installed directly into the root directory. However, all symlink mappings
are respected.
"""
mapping = {}

for target in targets:
info = target[DefaultInfo]

for file in info.files.to_list():
mapping[paths.join(prefix, "lib", file.basename)] = file

for link in info.default_runfiles.symlinks.to_list():
mapping[paths.join(prefix, link.path)] = link.target_file

for file in info.default_runfiles.files.to_list():
mapping[paths.join(prefix, file.path)] = file

return mapping

intellij_common = struct(
compute_plugin_layout = _compute_plugin_layout,
)
57 changes: 8 additions & 49 deletions build_defs/intellij_plugin.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -39,13 +39,6 @@ intellij_plugin(

load("@rules_java//java:defs.bzl", "JavaInfo", "java_binary", "java_common", "java_import")
load(":intellij_plugin_library.bzl", "OptionalPluginXmlInfo", "IntellijPluginLibraryInfo")
load(
"//build_defs:restrictions.bzl",
"RestrictedInfo",
"restricted_deps_aspect",
"validate_restrictions",
"validate_unchecked_internal",
)

def _optional_plugin_xml_impl(ctx):
attr = ctx.attr
Expand Down Expand Up @@ -243,27 +236,13 @@ def _intellij_plugin_jar_impl(ctx):
module_to_merged_xmls = _merge_optional_plugin_xmls(ctx)
final_plugin_xml_file = _add_optional_dependencies_to_plugin_xml(ctx, augmented_xml, [k.name for k in module_to_merged_xmls.keys() if not k.is_synthetic])
jar_file = _package_meta_inf_files(ctx, final_plugin_xml_file, module_to_merged_xmls)
files = depset([jar_file])

if ctx.attr.restrict_deps:
dependencies = {}
unchecked_transitive = []
roots = []
for k in ctx.attr.restricted_deps:
if RestrictedInfo in k:
dependencies.update(k[RestrictedInfo].dependencies)
unchecked_transitive.append(k[RestrictedInfo].unchecked)
roots.append(k[RestrictedInfo].roots)

# Uncomment the next line to see all buildable roots:
# fail("".join([" " + str(t) + "\n" for t in depset(transitive=roots).to_list()]))
validate_restrictions(dependencies)
unchecked = [str(t.label) for t in depset(direct = [], transitive = unchecked_transitive).to_list()]
validate_unchecked_internal(unchecked)

return DefaultInfo(
files = files,
)

runfiles = ctx.runfiles().merge_all([dep[IntellijPluginLibraryInfo].runfiles for dep in ctx.attr.deps])

return [
JavaInfo(output_jar = jar_file, compile_jar = jar_file),
DefaultInfo(files = depset([jar_file]), runfiles = runfiles),
]

_intellij_plugin_jar = rule(
implementation = _intellij_plugin_jar_impl,
Expand All @@ -273,8 +252,6 @@ _intellij_plugin_jar = rule(
"optional_plugin_xmls": attr.label_list(providers = [OptionalPluginXmlInfo]),
"jar_name": attr.string(mandatory = True),
"deps": attr.label_list(providers = [[IntellijPluginLibraryInfo]]),
"restrict_deps": attr.bool(),
"restricted_deps": attr.label_list(aspects = [restricted_deps_aspect]),
"plugin_icons": attr.label_list(allow_files = True),
"_merge_xml_binary": attr.label(
default = Label("//build_defs:merge_xml"),
Expand Down Expand Up @@ -302,9 +279,7 @@ def intellij_plugin(
jar_name = None,
extra_runtime_deps = [],
plugin_icons = [],
restrict_deps = False,
tags = [],
target_compatible_with = [],
testonly = 0,
**kwargs):
"""Creates an intellij plugin from the given deps and plugin.xml.
Expand All @@ -318,7 +293,6 @@ def intellij_plugin(
extra_runtime_deps: runtime_deps added to java_binary or java_test calls
plugin_icons: Plugin logo files to be placed in META-INF. Follow https://plugins.jetbrains.com/docs/intellij/plugin-icon-file.html#plugin-logo-requirements
tags: Tags to add to generated rules
target_compatible_with: To be passed through to generated rules
testonly: testonly setting for generated rules.
**kwargs: Any further arguments to be passed to the final target
"""
Expand All @@ -335,7 +309,6 @@ def intellij_plugin(
runtime_deps = [":" + java_deps_name] + extra_runtime_deps,
create_executable = 0,
tags = tags,
target_compatible_with = target_compatible_with,
testonly = testonly,
)

Expand All @@ -359,28 +332,14 @@ def intellij_plugin(
message = "Applying workarounds to plugin jar",
)

jar_target_name = name + "_intellij_plugin_jar"
_intellij_plugin_jar(
name = jar_target_name,
name = name,
deploy_jar = deploy_jar,
jar_name = jar_name or (name + ".jar"),
deps = deps,
restrict_deps = restrict_deps,
restricted_deps = deps if restrict_deps else [],
plugin_xml = plugin_xml,
optional_plugin_xmls = optional_plugin_xmls,
plugin_icons = plugin_icons,
tags = tags,
target_compatible_with = target_compatible_with,
testonly = testonly,
)

# included (with tag) as a hack so that IJwB can recognize this is an intellij plugin
java_import(
name = name,
jars = [jar_target_name],
tags = ["intellij-plugin"] + tags,
target_compatible_with = target_compatible_with,
testonly = testonly,
**kwargs
)
42 changes: 42 additions & 0 deletions build_defs/intellij_plugin_debug.bzl
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
load(":common.bzl", "intellij_common")

SUFFIX = ".intellij-plugin-debug-target-deploy-info"

def _create_deploy_location(path, file):
return struct(
execution_path = file.path,
deploy_location = path,
)

def _intellij_plugin_debug_target_impl(ctx):
output = ctx.actions.declare_file(ctx.label.name + SUFFIX)
layout = intellij_common.compute_plugin_layout(ctx.attr.prefix, ctx.attr.deps)

deploy_info = struct(
deploy_files = [_create_deploy_location(path, file) for path, file in layout.items()],
java_agent_deploy_files = [],
)

ctx.actions.write(output, proto.encode_text(deploy_info))

return [DefaultInfo(files = depset(layout.values() + [output]))]

intellij_plugin_debug_target = rule(
implementation = _intellij_plugin_debug_target_impl,
doc = """Creates plugin target debuggable from IntelliJ.

All files in deps are mapped into the plugin sandbox in the same mannar as they would be mapped
into the release zip.
""",
attrs = {
"deps": attr.label_list(
doc = "List of dependencies to deploy to the sandbox.",
allow_files = False,
mandatory = True,
),
"prefix": attr.string(
doc = "The directory name inside the plugins folder.",
mandatory = True,
),
},
)
Loading