-
Notifications
You must be signed in to change notification settings - Fork 80
/
nixpkgs.bzl
660 lines (598 loc) · 23 KB
/
nixpkgs.bzl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
"""Rules for importing Nixpkgs packages."""
load("@bazel_tools//tools/cpp:cc_configure.bzl", "cc_autoconf_impl")
load("@bazel_tools//tools/cpp:lib_cc_configure.bzl", "get_cpu_value")
def _nixpkgs_git_repository_impl(repository_ctx):
repository_ctx.file("BUILD")
# Make "@nixpkgs" (syntactic sugar for "@nixpkgs//:nixpkgs") a valid
# label for default.nix.
repository_ctx.symlink("default.nix", repository_ctx.name)
repository_ctx.download_and_extract(
url = "%s/archive/%s.tar.gz" % (repository_ctx.attr.remote, repository_ctx.attr.revision),
stripPrefix = "nixpkgs-" + repository_ctx.attr.revision,
sha256 = repository_ctx.attr.sha256,
)
nixpkgs_git_repository = repository_rule(
implementation = _nixpkgs_git_repository_impl,
attrs = {
"revision": attr.string(mandatory = True),
"remote": attr.string(default = "https://github.com/NixOS/nixpkgs"),
"sha256": attr.string(),
},
)
def _nixpkgs_local_repository_impl(repository_ctx):
repository_ctx.file("BUILD")
if not bool(repository_ctx.attr.nix_file) != \
bool(repository_ctx.attr.nix_file_content):
fail("Specify one of 'nix_file' or 'nix_file_content' (but not both).")
if repository_ctx.attr.nix_file_content:
repository_ctx.file(
path = "default.nix",
content = repository_ctx.attr.nix_file_content,
executable = False,
)
target = repository_ctx.path("default.nix")
else:
target = _cp(repository_ctx, repository_ctx.attr.nix_file)
for dep in repository_ctx.attr.nix_file_deps:
_cp(repository_ctx, dep)
# Make "@nixpkgs" (syntactic sugar for "@nixpkgs//:nixpkgs") a valid
# label for the target Nix file.
repository_ctx.symlink(target, repository_ctx.name)
nixpkgs_local_repository = repository_rule(
implementation = _nixpkgs_local_repository_impl,
attrs = {
"nix_file": attr.label(allow_single_file = [".nix"]),
"nix_file_deps": attr.label_list(),
"nix_file_content": attr.string(),
},
)
def _is_supported_platform(repository_ctx):
return repository_ctx.which("nix-build") != None
def _nixpkgs_package_impl(repository_ctx):
repository = repository_ctx.attr.repository
repositories = repository_ctx.attr.repositories
# Is nix supported on this platform?
not_supported = not _is_supported_platform(repository_ctx)
# Should we fail if Nix is not supported?
fail_not_supported = repository_ctx.attr.fail_not_supported
if repository and repositories or not repository and not repositories:
fail("Specify one of 'repository' or 'repositories' (but not both).")
elif repository:
repositories = {repository_ctx.attr.repository: "nixpkgs"}
# If true, a BUILD file will be created from a template if it does not
# exits.
# However this will happen AFTER the nix-build command.
create_build_file_if_needed = False
if repository_ctx.attr.build_file and repository_ctx.attr.build_file_content:
fail("Specify one of 'build_file' or 'build_file_content', but not both.")
elif repository_ctx.attr.build_file:
repository_ctx.symlink(repository_ctx.attr.build_file, "BUILD")
elif repository_ctx.attr.build_file_content:
repository_ctx.file("BUILD", content = repository_ctx.attr.build_file_content)
else:
# No user supplied build file, we may create the default one.
create_build_file_if_needed = True
strFailureImplicitNixpkgs = (
"One of 'repositories', 'nix_file' or 'nix_file_content' must be provided. " +
"The NIX_PATH environment variable is not inherited."
)
expr_args = []
if repository_ctx.attr.nix_file and repository_ctx.attr.nix_file_content:
fail("Specify one of 'nix_file' or 'nix_file_content', but not both.")
elif repository_ctx.attr.nix_file:
nix_file = _cp(repository_ctx, repository_ctx.attr.nix_file)
expr_args = [nix_file]
elif repository_ctx.attr.nix_file_content:
expr_args = ["-E", repository_ctx.attr.nix_file_content]
elif not repositories:
fail(strFailureImplicitNixpkgs)
else:
expr_args = ["-E", "import <nixpkgs> { config = {}; overlays = []; }"]
for dep in repository_ctx.attr.nix_file_deps:
_cp(repository_ctx, dep)
expr_args.extend([
"-A",
repository_ctx.attr.attribute_path if repository_ctx.attr.nix_file or repository_ctx.attr.nix_file_content else repository_ctx.attr.attribute_path or repository_ctx.attr.name,
# Creating an out link prevents nix from garbage collecting the store path.
# nixpkgs uses `nix-support/` for such house-keeping files, so we mirror them
# and use `bazel-support/`, under the assumption that no nix package has
# a file named `bazel-support` in its root.
# A `bazel clean` deletes the symlink and thus nix is free to garbage collect
# the store path.
"--out-link",
"bazel-support/nix-out-link",
])
expr_args.extend(repository_ctx.attr.nixopts)
# If repositories is not set, leave empty so nix will fail
# unless a pinned nixpkgs is set in the `nix_file` attribute.
nix_paths = []
if repositories:
nix_paths = [
(path_name + "=" + str(repository_ctx.path(target)))
for (target, path_name) in repositories.items()
]
elif not (repository_ctx.attr.nix_file or repository_ctx.attr.nix_file_content):
fail(strFailureImplicitNixpkgs)
for nix_path in nix_paths:
expr_args.extend(["-I", nix_path])
if not_supported and fail_not_supported:
fail("Platform is not supported (see 'fail_not_supported')")
elif not_supported:
return
else:
nix_build_path = _executable_path(
repository_ctx,
"nix-build",
extra_msg = "See: https://nixos.org/nix/",
)
nix_build = [nix_build_path] + expr_args
# Large enough integer that Bazel can still parse. We don't have
# access to MAX_INT and 0 is not a valid timeout so this is as good
# as we can do. The value shouldn't be too large to avoid errors on
# macOS, see https://github.com/tweag/rules_nixpkgs/issues/92.
timeout = 8640000
exec_result = _execute_or_fail(
repository_ctx,
nix_build,
failure_message = "Cannot build Nix attribute '{}'.".format(
repository_ctx.attr.attribute_path,
),
timeout = timeout,
)
output_path = exec_result.stdout.splitlines()[-1]
# ensure that the output is a directory
test_path = repository_ctx.which("test")
_execute_or_fail(
repository_ctx,
[test_path, "-d", output_path],
failure_message = "nixpkgs_package '@{}' outputs a single file which is not supported by rules_nixpkgs. Please only use directories.".format(
repository_ctx.name,
),
)
# Build a forest of symlinks (like new_local_package() does) to the
# Nix store.
for target in _find_children(repository_ctx, output_path):
basename = target.rpartition("/")[-1]
repository_ctx.symlink(target, basename)
# Create a default BUILD file only if it does not exists and is not
# provided by `build_file` or `build_file_content`.
if create_build_file_if_needed:
p = repository_ctx.path("BUILD")
if not p.exists:
repository_ctx.template("BUILD", Label("@io_tweag_rules_nixpkgs//nixpkgs:BUILD.pkg"))
_nixpkgs_package = repository_rule(
implementation = _nixpkgs_package_impl,
attrs = {
"attribute_path": attr.string(),
"nix_file": attr.label(allow_single_file = [".nix"]),
"nix_file_deps": attr.label_list(),
"nix_file_content": attr.string(),
"repositories": attr.label_keyed_string_dict(),
"repository": attr.label(),
"build_file": attr.label(),
"build_file_content": attr.string(),
"nixopts": attr.string_list(),
"fail_not_supported": attr.bool(default = True, doc = """
If set to True (default) this rule will fail on platforms which do not support Nix (e.g. Windows). If set to False calling this rule will succeed but no output will be generated.
"""),
},
)
def nixpkgs_package(*args, **kwargs):
# Because of https://github.com/bazelbuild/bazel/issues/7989 we can't
# directly pass a dict from strings to labels to the rule (which we'd like
# for the `repositories` arguments), but we can pass a dict from labels to
# strings. So we swap the keys and the values (assuming they all are
# distinct).
if "repositories" in kwargs:
inversed_repositories = {value: key for (key, value) in kwargs["repositories"].items()}
kwargs.pop("repositories")
_nixpkgs_package(
repositories = inversed_repositories,
*args,
**kwargs
)
else:
_nixpkgs_package(*args, **kwargs)
def _readlink(repository_ctx, path):
return repository_ctx.path(path).realpath
def nixpkgs_cc_autoconf_impl(repository_ctx):
cpu_value = get_cpu_value(repository_ctx)
if not _is_supported_platform(repository_ctx):
cc_autoconf_impl(repository_ctx)
return
# Calling repository_ctx.path() on anything but a regular file
# fails. So the roundabout way to do the same thing is to find
# a regular file we know is in the workspace (i.e. the WORKSPACE
# file itself) and then use dirname to get the path of the workspace
# root.
workspace_file_path = repository_ctx.path(
Label("@nixpkgs_cc_toolchain//:WORKSPACE"),
)
workspace_root = _execute_or_fail(
repository_ctx,
["dirname", workspace_file_path],
).stdout.rstrip()
# Make a list of all available tools in the Nix derivation. Override
# the Bazel autoconfiguration with the tools we found.
bin_contents = _find_children(repository_ctx, workspace_root + "/bin")
overriden_tools = {
tool: _readlink(repository_ctx, entry)
for entry in bin_contents
for tool in [entry.rpartition("/")[-1]] # Compute basename
}
cc_autoconf_impl(repository_ctx, overriden_tools = overriden_tools)
nixpkgs_cc_autoconf = repository_rule(
implementation = nixpkgs_cc_autoconf_impl,
# Copied from
# https://github.com/bazelbuild/bazel/blob/master/tools/cpp/cc_configure.bzl.
# Keep in sync.
environ = [
"ABI_LIBC_VERSION",
"ABI_VERSION",
"BAZEL_COMPILER",
"BAZEL_HOST_SYSTEM",
"BAZEL_LINKOPTS",
"BAZEL_PYTHON",
"BAZEL_SH",
"BAZEL_TARGET_CPU",
"BAZEL_TARGET_LIBC",
"BAZEL_TARGET_SYSTEM",
"BAZEL_USE_CPP_ONLY_TOOLCHAIN",
"BAZEL_DO_NOT_DETECT_CPP_TOOLCHAIN",
"BAZEL_USE_LLVM_NATIVE_COVERAGE",
"BAZEL_VC",
"BAZEL_VS",
"BAZEL_LLVM",
"USE_CLANG_CL",
"CC",
"CC_CONFIGURE_DEBUG",
"CC_TOOLCHAIN_NAME",
"CPLUS_INCLUDE_PATH",
"GCOV",
"HOMEBREW_RUBY_PATH",
"SYSTEMROOT",
"VS90COMNTOOLS",
"VS100COMNTOOLS",
"VS110COMNTOOLS",
"VS120COMNTOOLS",
"VS140COMNTOOLS",
],
)
def nixpkgs_cc_configure(
repository = None,
repositories = {},
nix_file = None,
nix_file_deps = None,
nix_file_content = None,
nixopts = []):
"""Use a CC toolchain from Nixpkgs. No-op if not a nix-based platform.
By default, Bazel auto-configures a CC toolchain from commands (e.g.
`gcc`) available in the environment. To make builds more hermetic, use
this rule to specific explicitly which commands the toolchain should
use.
"""
if not nix_file and not nix_file_content:
nix_file_content = """
with import <nixpkgs> { config = {}; overlays = []; }; buildEnv {
name = "bazel-cc-toolchain";
paths = [ stdenv.cc binutils ];
}
"""
nixpkgs_package(
name = "nixpkgs_cc_toolchain",
repository = repository,
repositories = repositories,
nix_file = nix_file,
nix_file_deps = nix_file_deps,
nix_file_content = nix_file_content,
build_file_content = """exports_files(glob(["bin/*"]))""",
nixopts = nixopts,
)
# Following lines should match
# https://github.com/bazelbuild/bazel/blob/master/tools/cpp/cc_configure.bzl#L93.
nixpkgs_cc_autoconf(name = "local_config_cc")
native.bind(name = "cc_toolchain", actual = "@local_config_cc//:toolchain")
native.register_toolchains("@local_config_cc//:all")
def _nixpkgs_python_toolchain_impl(repository_ctx):
cpu = get_cpu_value(repository_ctx)
repository_ctx.file("BUILD.bazel", executable = False, content = """
load("@bazel_tools//tools/python:toolchain.bzl", "py_runtime_pair")
py_runtime_pair(
name = "py_runtime_pair",
py2_runtime = {python2_runtime},
py3_runtime = {python3_runtime},
)
toolchain(
name = "toolchain",
toolchain = ":py_runtime_pair",
toolchain_type = "@bazel_tools//tools/python:toolchain_type",
exec_compatible_with = [
"@platforms//cpu:x86_64",
"@platforms//os:{os}",
"@io_tweag_rules_nixpkgs//nixpkgs/constraints:nixpkgs",
],
target_compatible_with = [
"@platforms//cpu:x86_64",
"@platforms//os:{os}",
],
)
""".format(
python2_runtime = _label_string(repository_ctx.attr.python2_runtime),
python3_runtime = _label_string(repository_ctx.attr.python3_runtime),
os = {"darwin": "osx"}.get(cpu, "linux"),
))
_nixpkgs_python_toolchain = repository_rule(
_nixpkgs_python_toolchain_impl,
attrs = {
# Using attr.string instead of attr.label, so that the repository rule
# does not explicitly depend on the nixpkgs_package instances. This is
# necessary, so that builds don't fail on platforms without nixpkgs.
"python2_runtime": attr.string(),
"python3_runtime": attr.string(),
},
)
_python_nix_file_content = """
with import <nixpkgs> {{ config = {{}}; overlays = []; }};
runCommand "bazel-nixpkgs-python-toolchain"
{{ executable = false;
# Pointless to do this on a remote machine.
preferLocalBuild = true;
allowSubstitutes = false;
}}
''
n=$out/BUILD.bazel
mkdir -p "$(dirname "$n")"
cat >>$n <<EOF
py_runtime(
name = "runtime",
interpreter_path = "${{{attribute_path}}}/{bin_path}",
python_version = "{version}",
visibility = ["//visibility:public"],
)
EOF
''
"""
def nixpkgs_python_configure(
name = "nixpkgs_python_toolchain",
python2_attribute_path = None,
python2_bin_path = "bin/python",
python3_attribute_path = "python3",
python3_bin_path = "bin/python",
repository = None,
repositories = {},
nix_file_deps = None,
nixopts = [],
fail_not_supported = True):
"""Define and register a Python toolchain provided by nixpkgs.
Creates `nixpkgs_package`s for Python 2 or 3 `py_runtime` instances and a
corresponding `py_runtime_pair` and `toolchain`. The toolchain is
automatically registered and uses the constraint:
"@io_tweag_rules_nixpkgs//nixpkgs/constraints:nixpkgs"
Attrs:
name: The name-prefix for the created external repositories.
python2_attribute_path: The nixpkgs attribute path for python2.
python2_bin_path: The path to the interpreter within the package.
python3_attribute_path: The nixpkgs attribute path for python3.
python3_bin_path: The path to the interpreter within the package.
...: See `nixpkgs_package` for the remaining attributes.
"""
python2_specified = python2_attribute_path and python2_bin_path
python3_specified = python3_attribute_path and python3_bin_path
if not python2_specified and not python3_specified:
fail("At least one of python2 or python3 has to be specified.")
kwargs = dict(
repository = repository,
repositories = repositories,
nix_file_deps = nix_file_deps,
nixopts = nixopts,
fail_not_supported = fail_not_supported,
)
python2_runtime = None
if python2_attribute_path:
python2_runtime = "@%s_python2//:runtime" % name
nixpkgs_package(
name = name + "_python2",
nix_file_content = _python_nix_file_content.format(
attribute_path = python2_attribute_path,
bin_path = python2_bin_path,
version = "PY2",
),
**kwargs
)
python3_runtime = None
if python3_attribute_path:
python3_runtime = "@%s_python3//:runtime" % name
nixpkgs_package(
name = name + "_python3",
nix_file_content = _python_nix_file_content.format(
attribute_path = python3_attribute_path,
bin_path = python3_bin_path,
version = "PY3",
),
**kwargs
)
_nixpkgs_python_toolchain(
name = name,
python2_runtime = python2_runtime,
python3_runtime = python3_runtime,
)
native.register_toolchains("@%s//:toolchain" % name)
def nixpkgs_sh_posix_config(name, packages, **kwargs):
nixpkgs_package(
name = name,
nix_file_content = """
with import <nixpkgs> {{ config = {{}}; overlays = []; }};
let
# `packages` might include lists, e.g. `stdenv.initialPath` is a list itself,
# so we need to flatten `packages`.
flatten = builtins.concatMap (x: if builtins.isList x then x else [x]);
env = buildEnv {{
name = "posix-toolchain";
paths = flatten [ {} ];
}};
cmd_glob = "${{env}}/bin/*";
os = if stdenv.isDarwin then "osx" else "linux";
in
runCommand "bazel-nixpkgs-posix-toolchain"
{{ executable = false;
# Pointless to do this on a remote machine.
preferLocalBuild = true;
allowSubstitutes = false;
}}
''
n=$out/nixpkgs_sh_posix.bzl
mkdir -p "$(dirname "$n")"
cat >>$n <<EOF
load("@rules_sh//sh:posix.bzl", "posix", "sh_posix_toolchain")
discovered = {{
EOF
for cmd in ${{cmd_glob}}; do
if [[ -x $cmd ]]; then
echo " '$(basename $cmd)': '$cmd'," >>$n
fi
done
cat >>$n <<EOF
}}
def create_posix_toolchain():
sh_posix_toolchain(
name = "nixpkgs_sh_posix",
**{{
cmd: discovered[cmd]
for cmd in posix.commands
if cmd in discovered
}}
)
EOF
''
""".format(" ".join(packages)),
build_file_content = """
load("//:nixpkgs_sh_posix.bzl", "create_posix_toolchain")
create_posix_toolchain()
""",
**kwargs
)
def _nixpkgs_sh_posix_toolchain_impl(repository_ctx):
cpu = get_cpu_value(repository_ctx)
repository_ctx.file("BUILD", executable = False, content = """
toolchain(
name = "nixpkgs_sh_posix_toolchain",
toolchain = "@{workspace}//:nixpkgs_sh_posix",
toolchain_type = "@rules_sh//sh/posix:toolchain_type",
exec_compatible_with = [
"@platforms//cpu:x86_64",
"@platforms//os:{os}",
"@io_tweag_rules_nixpkgs//nixpkgs/constraints:nixpkgs",
],
target_compatible_with = [
"@platforms//cpu:x86_64",
"@platforms//os:{os}",
],
)
""".format(
workspace = repository_ctx.attr.workspace,
os = {"darwin": "osx"}.get(cpu, "linux"),
))
_nixpkgs_sh_posix_toolchain = repository_rule(
_nixpkgs_sh_posix_toolchain_impl,
attrs = {
"workspace": attr.string(),
},
)
def nixpkgs_sh_posix_configure(
name = "nixpkgs_sh_posix_config",
packages = ["stdenv.initialPath"],
**kwargs):
"""Create a POSIX toolchain from nixpkgs.
Loads the given Nix packages, scans them for standard Unix tools, and
generates a corresponding `sh_posix_toolchain`.
Make sure to call `nixpkgs_sh_posix_configure` before `sh_posix_configure`,
if you use both. Otherwise, the local toolchain will always be chosen in
favor of the nixpkgs one.
Args:
name: Name prefix for the generated repositories.
packages: List of Nix attribute paths to draw Unix tools from.
nix_file_deps: See nixpkgs_package.
repositories: See nixpkgs_package.
repository: See nixpkgs_package.
nixopts: See nixpkgs_package.
fail_not_supported: See nixpkgs_package.
"""
nixpkgs_sh_posix_config(
name = name,
packages = packages,
**kwargs
)
# The indirection is required to avoid errors when `nix-build` is not in `PATH`.
_nixpkgs_sh_posix_toolchain(
name = name + "_toolchain",
workspace = name,
)
native.register_toolchains(
"@{}//:nixpkgs_sh_posix_toolchain".format(name + "_toolchain"),
)
def _execute_or_fail(repository_ctx, arguments, failure_message = "", *args, **kwargs):
"""Call repository_ctx.execute() and fail if non-zero return code."""
result = repository_ctx.execute(arguments, *args, **kwargs)
if result.return_code:
outputs = dict(
failure_message = failure_message,
arguments = arguments,
return_code = result.return_code,
stderr = result.stderr,
)
fail("""
{failure_message}
Command: {arguments}
Return code: {return_code}
Error output:
{stderr}
""".format(**outputs))
return result
def _find_children(repository_ctx, target_dir):
find_args = [
_executable_path(repository_ctx, "find"),
"-L",
target_dir,
"-maxdepth",
"1",
# otherwise the directory is printed as well
"-mindepth",
"1",
# filenames can contain \n
"-print0",
]
exec_result = _execute_or_fail(repository_ctx, find_args)
return exec_result.stdout.rstrip("\000").split("\000")
def _executable_path(repository_ctx, exe_name, extra_msg = ""):
"""Try to find the executable, fail with an error."""
path = repository_ctx.which(exe_name)
if path == None:
fail("Could not find the `{}` executable in PATH.{}\n"
.format(exe_name, " " + extra_msg if extra_msg else ""))
return path
def _cp(repository_ctx, src, dest = None):
"""Copy the given file into the external repository root.
Args:
repository_ctx: The repository context of the current repository rule.
src: The source file. Must be a Label if dest is None.
dest: Optional, The target path within the current repository root.
By default the relative path to the repository root is preserved.
Returns:
The absolute target path.
"""
if dest == None:
if type(src) != "Label":
fail("src must be a Label if dest is not specified explicitly.")
dest = "/".join([
component
for component in [src.workspace_root, src.package, src.name]
if component
])
repository_ctx.template(dest, src, executable = False)
return repository_ctx.path(dest)
def _label_string(label):
"""Convert the given (optional) Label to a string."""
if not label:
return "None"
else:
return '"%s"' % label