Skip to content

Commit aa11bfc

Browse files
JamyDevlinzhp
andauthored
feat(bazel): support archive mode (#259)
Removes the broken reflect mode in the bazel aspect, in favor of archive mode which was landed in #258 --------- Co-authored-by: Zhongpeng Lin <[email protected]>
1 parent 359202c commit aa11bfc

File tree

3 files changed

+43
-154
lines changed

3 files changed

+43
-154
lines changed

bazel/go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,4 @@ module go.uber.org/mock/bazel
22

33
go 1.23.0
44

5-
require go.uber.org/mock v0.4.0
5+
require go.uber.org/mock v0.5.3-0.20250612195617-359202c7b2fe

bazel/go.sum

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
go.uber.org/mock v0.4.0 h1:VcM4ZOtdbR4f6VXfiOpwpVJDL6lCReaZ6mw31wqh7KU=
2-
go.uber.org/mock v0.4.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc=
1+
go.uber.org/mock v0.5.3-0.20250612195617-359202c7b2fe h1:RZLb3fA2lGyj9wI0+49h3liYevFS0HC3gb1j/CocDOU=
2+
go.uber.org/mock v0.5.3-0.20250612195617-359202c7b2fe/go.mod h1:wLlUxC2vVTPTaE3UD51E0BGOAElKrILxhVSDYQLld5o=

bazel/rules/gomock.bzl

Lines changed: 40 additions & 151 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
load("@bazel_skylib//lib:paths.bzl", "paths")
2626
load("@io_bazel_rules_go//go/private:common.bzl", "GO_TOOLCHAIN", "GO_TOOLCHAIN_LABEL")
2727
load("@io_bazel_rules_go//go/private:context.bzl", "go_context")
28-
load("@io_bazel_rules_go//go/private:providers.bzl", "GoInfo")
28+
load("@io_bazel_rules_go//go/private:providers.bzl", "GoArchive", "GoInfo")
2929
load("@io_bazel_rules_go//go/private/rules:wrappers.bzl", go_binary = "go_binary_macro")
3030

3131
_MOCKGEN_TOOL = Label("@org_uber_go_mock//mockgen")
@@ -214,193 +214,82 @@ def gomock(name, out, library = None, source_importpath = "", source = None, int
214214
**kwargs
215215
)
216216
else:
217-
_gomock_reflect(
217+
_gomock_archive(
218218
name = name,
219219
out = out,
220220
library = library,
221221
interfaces = interfaces,
222222
package = package,
223223
self_package = self_package,
224224
mockgen_tool = mockgen_tool,
225-
mockgen_args = mockgen_args,
226-
imports = imports,
227225
copyright_file = copyright_file,
228-
mock_names = mock_names,
229226
**kwargs
230227
)
231228

232-
def _gomock_reflect(name, library, out, mockgen_tool, **kwargs):
233-
interfaces = kwargs.pop("interfaces", None)
234-
mockgen_model_lib = kwargs.pop("mockgen_model_library", _MOCKGEN_MODEL_LIB)
235-
236-
prog_src = name + "_gomock_prog"
237-
prog_src_out = prog_src + ".go"
238-
_gomock_prog_gen(
239-
name = prog_src,
240-
interfaces = interfaces,
241-
library = library,
242-
out = prog_src_out,
243-
mockgen_tool = mockgen_tool,
244-
)
245-
prog_bin = name + "_gomock_prog_bin"
246-
go_binary(
247-
name = prog_bin,
248-
srcs = [prog_src_out],
249-
deps = [library, mockgen_model_lib],
250-
)
251-
_gomock_prog_exec(
252-
name = name,
253-
interfaces = interfaces,
254-
library = library,
255-
out = out,
256-
prog_bin = prog_bin,
257-
mockgen_tool = mockgen_tool,
258-
**kwargs
259-
)
260-
261-
def _gomock_prog_gen_impl(ctx):
262-
args = ["-prog_only"]
263-
args.append(ctx.attr.library[GoInfo].importpath)
264-
args.append(",".join(ctx.attr.interfaces))
265-
266-
cmd = ctx.file.mockgen_tool
267-
out = ctx.outputs.out
268-
ctx.actions.run_shell(
269-
outputs = [out],
270-
tools = [cmd],
229+
def _gomock_archive_impl(ctx):
230+
args = ctx.actions.args()
231+
args.add("-package", ctx.attr.library[GoInfo].importpath)
232+
args.add("-archive", ctx.attr.library[GoArchive].data.export_file.path)
233+
args.add("-destination", ctx.outputs.out)
234+
args.add("-package", ctx.attr.package)
235+
args.add("-self_package", ctx.attr.self_package)
236+
args.add(ctx.attr.library[GoInfo].importpath)
237+
args.add_joined(ctx.attr.interfaces, join_with = ",")
238+
239+
# Porting in fix for x/tools >= 0.27.0 from https://github.com/bazel-contrib/rules_go/pull/4173
240+
go_ctx = go_context(ctx)
241+
go_ctx.actions.run_shell(
242+
outputs = [ctx.outputs.out],
243+
inputs = [ctx.attr.library[GoArchive].data.export_file],
244+
arguments = [args],
245+
tools = [ctx.executable.mockgen_tool, go_ctx.sdk.go],
271246
command = """
272-
{cmd} {args} > {out}
247+
export PATH=$(pwd)/$(dirname {go}):$PATH &&
248+
export GOROOT=$(pwd)/{goroot} &&
249+
{cmd} "$@"
273250
""".format(
274-
cmd = "$(pwd)/" + cmd.path,
275-
args = " ".join(args),
276-
out = out.path,
251+
go = go_ctx.go.path,
252+
goroot = go_ctx.sdk.root_file.dirname,
253+
cmd = ctx.executable.mockgen_tool.path,
277254
),
278-
mnemonic = "GoMockReflectProgOnlyGen",
255+
mnemonic = "GoMockArchiveGen",
279256
)
280257

281-
_gomock_prog_gen = rule(
282-
_gomock_prog_gen_impl,
258+
_gomock_archive = rule(
259+
_gomock_archive_impl,
283260
attrs = {
284261
"library": attr.label(
285-
doc = "The target the Go library is at to look for the interfaces in. When this is set and source is not set, mockgen will use its reflect code to generate the mocks. If source is set, its dependencies will be included in the GOPATH that mockgen will be run in.",
286-
providers = [GoInfo],
287-
mandatory = True,
288-
),
289-
"out": attr.output(
290-
doc = "The new Go source file put the mock generator code",
262+
providers = [GoInfo, GoArchive],
291263
mandatory = True,
264+
doc = "The library that contains the interfaces to mock.",
292265
),
293-
"interfaces": attr.string_list(
294-
allow_empty = False,
295-
doc = "The names of the Go interfaces to generate mocks for. If not set, all of the interfaces in the library or source file will have mocks generated for them.",
296-
mandatory = True,
297-
),
298-
"mockgen_tool": attr.label(
299-
doc = "The mockgen tool to run",
300-
default = _MOCKGEN_TOOL,
266+
"copyright_file": attr.label(
267+
doc = "Optional file containing copyright to prepend to the generated contents.",
301268
allow_single_file = True,
302-
executable = True,
303-
cfg = "exec",
304269
mandatory = False,
305270
),
306-
"_go_context_data": attr.label(
307-
default = "@io_bazel_rules_go//:go_context_data",
308-
),
309-
},
310-
toolchains = [GO_TOOLCHAIN],
311-
)
312-
313-
def _gomock_prog_exec_impl(ctx):
314-
go = go_context(ctx, include_deprecated_properties = False)
315-
316-
args = ["-exec_only", ctx.file.prog_bin.path]
317-
args, needed_files = _handle_shared_args(ctx, args)
318-
319-
# annoyingly, the interfaces join has to go after the importpath so we can't
320-
# share those.
321-
args.append(ctx.attr.library[GoInfo].importpath)
322-
args.append(",".join(ctx.attr.interfaces))
323-
324-
ctx.actions.run_shell(
325-
outputs = [ctx.outputs.out],
326-
inputs = needed_files + [ctx.file.prog_bin, go.sdk.go],
327-
tools = [
328-
ctx.file.mockgen_tool,
329-
go.sdk.go,
330-
],
331-
command = """
332-
export GOROOT=$(pwd)/{goroot} &&
333-
export PATH=$GOROOT/bin:$PATH &&
334-
{cmd} {args} > {out}""".format(
335-
goroot = go.sdk.root_file.dirname,
336-
cmd = "$(pwd)/" + ctx.file.mockgen_tool.path,
337-
args = " ".join(args),
338-
out = ctx.outputs.out.path,
339-
),
340-
env = {
341-
# GOCACHE is required starting in Go 1.12
342-
"GOCACHE": "./.gocache",
343-
},
344-
mnemonic = "GoMockReflectExecOnlyGen",
345-
)
346-
347-
_gomock_prog_exec = rule(
348-
_gomock_prog_exec_impl,
349-
attrs = {
350-
"library": attr.label(
351-
doc = "The target the Go library is at to look for the interfaces in. When this is set and source is not set, mockgen will use its reflect code to generate the mocks. If source is set, its dependencies will be included in the GOPATH that mockgen will be run in.",
352-
providers = [GoInfo],
353-
mandatory = True,
354-
),
355271
"out": attr.output(
356-
doc = "The new Go source file to put the generated mock code",
357272
mandatory = True,
273+
doc = "The new Go source file to put the generated mock code.",
358274
),
359275
"interfaces": attr.string_list(
360-
allow_empty = False,
361-
doc = "The names of the Go interfaces to generate mocks for. If not set, all of the interfaces in the library or source file will have mocks generated for them.",
362-
mandatory = True,
276+
allow_empty = True,
277+
doc = "Interfaces to mock.",
363278
),
364279
"package": attr.string(
365280
doc = "The name of the package the generated mocks should be in. If not specified, uses mockgen's default.",
366281
),
367282
"self_package": attr.string(
368-
doc = "The full package import path for the generated code. The purpose of this flag is to prevent import cycles in the generated code by trying to include its own package. This can happen if the mock's package is set to one of its inputs (usually the main one) and the output is stdio so mockgen cannot detect the final output package. Setting this flag will then tell mockgen which import to exclude.",
369-
),
370-
"imports": attr.string_dict(
371-
doc = "Dictionary of name-path pairs of explicit imports to use.",
372-
),
373-
"mock_names": attr.string_dict(
374-
doc = "Dictionary of interfaceName-mockName pairs of explicit mock names to use. Mock names default to 'Mock'+ interfaceName suffix.",
375-
default = {},
376-
),
377-
"copyright_file": attr.label(
378-
doc = "Optional file containing copyright to prepend to the generated contents.",
379-
allow_single_file = True,
380-
mandatory = False,
381-
),
382-
"prog_bin": attr.label(
383-
doc = "The program binary generated by mockgen's -prog_only and compiled by bazel.",
384-
allow_single_file = True,
385-
executable = True,
386-
cfg = "exec",
387-
mandatory = True,
283+
doc = "The full package import path for the generated code.",
388284
),
389285
"mockgen_tool": attr.label(
390-
doc = "The mockgen tool to run",
391-
default = _MOCKGEN_TOOL,
392-
allow_single_file = True,
286+
default = Label("@com_github_golang_mock//mockgen"),
393287
executable = True,
394288
cfg = "exec",
395-
mandatory = False,
396289
),
397-
"mockgen_args": attr.string_list(
398-
doc = "Additional arguments to pass to the mockgen tool",
399-
mandatory = False,
400-
default = [],
401-
),
402-
"_go_context_data": attr.label(
403-
default = "@io_bazel_rules_go//:go_context_data",
290+
"use_underlying_names": attr.bool(
291+
doc = "Use alias underlying type names in generated mocks instead of the alias names directly",
292+
default = False,
404293
),
405294
},
406295
toolchains = [GO_TOOLCHAIN],

0 commit comments

Comments
 (0)