• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# pylint: disable=g-bad-file-header
2# Copyright 2018 The Bazel Authors. All rights reserved.
3#
4# Licensed under the Apache License, Version 2.0 (the "License");
5# you may not use this file except in compliance with the License.
6# You may obtain a copy of the License at
7#
8#    http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS,
12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13# See the License for the specific language governing permissions and
14# limitations under the License.
15
16import os
17import tempfile
18import unittest
19
20from python.runfiles import runfiles
21
22
23class RunfilesTest(unittest.TestCase):
24    # """Unit tests for `runfiles.Runfiles`."""
25
26    def testRlocationArgumentValidation(self):
27        r = runfiles.Create({"RUNFILES_DIR": "whatever"})
28        self.assertRaises(ValueError, lambda: r.Rlocation(None))
29        self.assertRaises(ValueError, lambda: r.Rlocation(""))
30        self.assertRaises(TypeError, lambda: r.Rlocation(1))
31        self.assertRaisesRegex(
32            ValueError, "is not normalized", lambda: r.Rlocation("../foo")
33        )
34        self.assertRaisesRegex(
35            ValueError, "is not normalized", lambda: r.Rlocation("foo/..")
36        )
37        self.assertRaisesRegex(
38            ValueError, "is not normalized", lambda: r.Rlocation("foo/../bar")
39        )
40        self.assertRaisesRegex(
41            ValueError, "is not normalized", lambda: r.Rlocation("./foo")
42        )
43        self.assertRaisesRegex(
44            ValueError, "is not normalized", lambda: r.Rlocation("foo/.")
45        )
46        self.assertRaisesRegex(
47            ValueError, "is not normalized", lambda: r.Rlocation("foo/./bar")
48        )
49        self.assertRaisesRegex(
50            ValueError, "is not normalized", lambda: r.Rlocation("//foobar")
51        )
52        self.assertRaisesRegex(
53            ValueError, "is not normalized", lambda: r.Rlocation("foo//")
54        )
55        self.assertRaisesRegex(
56            ValueError, "is not normalized", lambda: r.Rlocation("foo//bar")
57        )
58        self.assertRaisesRegex(
59            ValueError,
60            "is absolute without a drive letter",
61            lambda: r.Rlocation("\\foo"),
62        )
63
64    def testCreatesManifestBasedRunfiles(self):
65        with _MockFile(contents=["a/b c/d"]) as mf:
66            r = runfiles.Create(
67                {
68                    "RUNFILES_MANIFEST_FILE": mf.Path(),
69                    "RUNFILES_DIR": "ignored when RUNFILES_MANIFEST_FILE has a value",
70                    "TEST_SRCDIR": "always ignored",
71                }
72            )
73            self.assertEqual(r.Rlocation("a/b"), "c/d")
74            self.assertIsNone(r.Rlocation("foo"))
75
76    def testManifestBasedRunfilesEnvVars(self):
77        with _MockFile(name="MANIFEST") as mf:
78            r = runfiles.Create(
79                {
80                    "RUNFILES_MANIFEST_FILE": mf.Path(),
81                    "TEST_SRCDIR": "always ignored",
82                }
83            )
84            self.assertDictEqual(
85                r.EnvVars(),
86                {
87                    "RUNFILES_MANIFEST_FILE": mf.Path(),
88                    "RUNFILES_DIR": mf.Path()[: -len("/MANIFEST")],
89                    "JAVA_RUNFILES": mf.Path()[: -len("/MANIFEST")],
90                },
91            )
92
93        with _MockFile(name="foo.runfiles_manifest") as mf:
94            r = runfiles.Create(
95                {
96                    "RUNFILES_MANIFEST_FILE": mf.Path(),
97                    "TEST_SRCDIR": "always ignored",
98                }
99            )
100            self.assertDictEqual(
101                r.EnvVars(),
102                {
103                    "RUNFILES_MANIFEST_FILE": mf.Path(),
104                    "RUNFILES_DIR": (
105                        mf.Path()[: -len("foo.runfiles_manifest")] + "foo.runfiles"
106                    ),
107                    "JAVA_RUNFILES": (
108                        mf.Path()[: -len("foo.runfiles_manifest")] + "foo.runfiles"
109                    ),
110                },
111            )
112
113        with _MockFile(name="x_manifest") as mf:
114            r = runfiles.Create(
115                {
116                    "RUNFILES_MANIFEST_FILE": mf.Path(),
117                    "TEST_SRCDIR": "always ignored",
118                }
119            )
120            self.assertDictEqual(
121                r.EnvVars(),
122                {
123                    "RUNFILES_MANIFEST_FILE": mf.Path(),
124                    "RUNFILES_DIR": "",
125                    "JAVA_RUNFILES": "",
126                },
127            )
128
129    def testCreatesDirectoryBasedRunfiles(self):
130        r = runfiles.Create(
131            {
132                "RUNFILES_DIR": "runfiles/dir",
133                "TEST_SRCDIR": "always ignored",
134            }
135        )
136        self.assertEqual(r.Rlocation("a/b"), "runfiles/dir/a/b")
137        self.assertEqual(r.Rlocation("foo"), "runfiles/dir/foo")
138
139    def testDirectoryBasedRunfilesEnvVars(self):
140        r = runfiles.Create(
141            {
142                "RUNFILES_DIR": "runfiles/dir",
143                "TEST_SRCDIR": "always ignored",
144            }
145        )
146        self.assertDictEqual(
147            r.EnvVars(),
148            {
149                "RUNFILES_DIR": "runfiles/dir",
150                "JAVA_RUNFILES": "runfiles/dir",
151            },
152        )
153
154    def testFailsToCreateManifestBasedBecauseManifestDoesNotExist(self):
155        def _Run():
156            runfiles.Create({"RUNFILES_MANIFEST_FILE": "non-existing path"})
157
158        self.assertRaisesRegex(IOError, "non-existing path", _Run)
159
160    def testFailsToCreateAnyRunfilesBecauseEnvvarsAreNotDefined(self):
161        with _MockFile(contents=["a b"]) as mf:
162            runfiles.Create(
163                {
164                    "RUNFILES_MANIFEST_FILE": mf.Path(),
165                    "RUNFILES_DIR": "whatever",
166                    "TEST_SRCDIR": "always ignored",
167                }
168            )
169        runfiles.Create(
170            {
171                "RUNFILES_DIR": "whatever",
172                "TEST_SRCDIR": "always ignored",
173            }
174        )
175        self.assertIsNone(runfiles.Create({"TEST_SRCDIR": "always ignored"}))
176        self.assertIsNone(runfiles.Create({"FOO": "bar"}))
177
178    def testManifestBasedRlocation(self):
179        with _MockFile(
180            contents=[
181                "Foo/runfile1",
182                "Foo/runfile2 C:/Actual Path\\runfile2",
183                "Foo/Bar/runfile3 D:\\the path\\run file 3.txt",
184                "Foo/Bar/Dir E:\\Actual Path\\Directory",
185            ]
186        ) as mf:
187            r = runfiles.CreateManifestBased(mf.Path())
188            self.assertEqual(r.Rlocation("Foo/runfile1"), "Foo/runfile1")
189            self.assertEqual(r.Rlocation("Foo/runfile2"), "C:/Actual Path\\runfile2")
190            self.assertEqual(
191                r.Rlocation("Foo/Bar/runfile3"), "D:\\the path\\run file 3.txt"
192            )
193            self.assertEqual(
194                r.Rlocation("Foo/Bar/Dir/runfile4"),
195                "E:\\Actual Path\\Directory/runfile4",
196            )
197            self.assertEqual(
198                r.Rlocation("Foo/Bar/Dir/Deeply/Nested/runfile4"),
199                "E:\\Actual Path\\Directory/Deeply/Nested/runfile4",
200            )
201            self.assertIsNone(r.Rlocation("unknown"))
202            if RunfilesTest.IsWindows():
203                self.assertEqual(r.Rlocation("c:/foo"), "c:/foo")
204                self.assertEqual(r.Rlocation("c:\\foo"), "c:\\foo")
205            else:
206                self.assertEqual(r.Rlocation("/foo"), "/foo")
207
208    def testManifestBasedRlocationWithRepoMappingFromMain(self):
209        with _MockFile(
210            contents=[
211                ",config.json,config.json~1.2.3",
212                ",my_module,_main",
213                ",my_protobuf,protobuf~3.19.2",
214                ",my_workspace,_main",
215                "protobuf~3.19.2,config.json,config.json~1.2.3",
216                "protobuf~3.19.2,protobuf,protobuf~3.19.2",
217            ]
218        ) as rm, _MockFile(
219            contents=[
220                "_repo_mapping " + rm.Path(),
221                "config.json /etc/config.json",
222                "protobuf~3.19.2/foo/runfile C:/Actual Path\\protobuf\\runfile",
223                "_main/bar/runfile /the/path/./to/other//other runfile.txt",
224                "protobuf~3.19.2/bar/dir E:\\Actual Path\\Directory",
225            ],
226        ) as mf:
227            r = runfiles.CreateManifestBased(mf.Path())
228
229            self.assertEqual(
230                r.Rlocation("my_module/bar/runfile", ""),
231                "/the/path/./to/other//other runfile.txt",
232            )
233            self.assertEqual(
234                r.Rlocation("my_workspace/bar/runfile", ""),
235                "/the/path/./to/other//other runfile.txt",
236            )
237            self.assertEqual(
238                r.Rlocation("my_protobuf/foo/runfile", ""),
239                "C:/Actual Path\\protobuf\\runfile",
240            )
241            self.assertEqual(
242                r.Rlocation("my_protobuf/bar/dir", ""), "E:\\Actual Path\\Directory"
243            )
244            self.assertEqual(
245                r.Rlocation("my_protobuf/bar/dir/file", ""),
246                "E:\\Actual Path\\Directory/file",
247            )
248            self.assertEqual(
249                r.Rlocation("my_protobuf/bar/dir/de eply/nes ted/fi~le", ""),
250                "E:\\Actual Path\\Directory/de eply/nes ted/fi~le",
251            )
252
253            self.assertIsNone(r.Rlocation("protobuf/foo/runfile"))
254            self.assertIsNone(r.Rlocation("protobuf/bar/dir"))
255            self.assertIsNone(r.Rlocation("protobuf/bar/dir/file"))
256            self.assertIsNone(r.Rlocation("protobuf/bar/dir/dir/de eply/nes ted/fi~le"))
257
258            self.assertEqual(
259                r.Rlocation("_main/bar/runfile", ""),
260                "/the/path/./to/other//other runfile.txt",
261            )
262            self.assertEqual(
263                r.Rlocation("protobuf~3.19.2/foo/runfile", ""),
264                "C:/Actual Path\\protobuf\\runfile",
265            )
266            self.assertEqual(
267                r.Rlocation("protobuf~3.19.2/bar/dir", ""), "E:\\Actual Path\\Directory"
268            )
269            self.assertEqual(
270                r.Rlocation("protobuf~3.19.2/bar/dir/file", ""),
271                "E:\\Actual Path\\Directory/file",
272            )
273            self.assertEqual(
274                r.Rlocation("protobuf~3.19.2/bar/dir/de eply/nes  ted/fi~le", ""),
275                "E:\\Actual Path\\Directory/de eply/nes  ted/fi~le",
276            )
277
278            self.assertEqual(r.Rlocation("config.json", ""), "/etc/config.json")
279            self.assertIsNone(r.Rlocation("_main", ""))
280            self.assertIsNone(r.Rlocation("my_module", ""))
281            self.assertIsNone(r.Rlocation("protobuf", ""))
282
283    def testManifestBasedRlocationWithRepoMappingFromOtherRepo(self):
284        with _MockFile(
285            contents=[
286                ",config.json,config.json~1.2.3",
287                ",my_module,_main",
288                ",my_protobuf,protobuf~3.19.2",
289                ",my_workspace,_main",
290                "protobuf~3.19.2,config.json,config.json~1.2.3",
291                "protobuf~3.19.2,protobuf,protobuf~3.19.2",
292            ]
293        ) as rm, _MockFile(
294            contents=[
295                "_repo_mapping " + rm.Path(),
296                "config.json /etc/config.json",
297                "protobuf~3.19.2/foo/runfile C:/Actual Path\\protobuf\\runfile",
298                "_main/bar/runfile /the/path/./to/other//other runfile.txt",
299                "protobuf~3.19.2/bar/dir E:\\Actual Path\\Directory",
300            ],
301        ) as mf:
302            r = runfiles.CreateManifestBased(mf.Path())
303
304            self.assertEqual(
305                r.Rlocation("protobuf/foo/runfile", "protobuf~3.19.2"),
306                "C:/Actual Path\\protobuf\\runfile",
307            )
308            self.assertEqual(
309                r.Rlocation("protobuf/bar/dir", "protobuf~3.19.2"),
310                "E:\\Actual Path\\Directory",
311            )
312            self.assertEqual(
313                r.Rlocation("protobuf/bar/dir/file", "protobuf~3.19.2"),
314                "E:\\Actual Path\\Directory/file",
315            )
316            self.assertEqual(
317                r.Rlocation(
318                    "protobuf/bar/dir/de eply/nes  ted/fi~le", "protobuf~3.19.2"
319                ),
320                "E:\\Actual Path\\Directory/de eply/nes  ted/fi~le",
321            )
322
323            self.assertIsNone(r.Rlocation("my_module/bar/runfile", "protobuf~3.19.2"))
324            self.assertIsNone(r.Rlocation("my_protobuf/foo/runfile", "protobuf~3.19.2"))
325            self.assertIsNone(r.Rlocation("my_protobuf/bar/dir", "protobuf~3.19.2"))
326            self.assertIsNone(
327                r.Rlocation("my_protobuf/bar/dir/file", "protobuf~3.19.2")
328            )
329            self.assertIsNone(
330                r.Rlocation(
331                    "my_protobuf/bar/dir/de eply/nes  ted/fi~le", "protobuf~3.19.2"
332                )
333            )
334
335            self.assertEqual(
336                r.Rlocation("_main/bar/runfile", "protobuf~3.19.2"),
337                "/the/path/./to/other//other runfile.txt",
338            )
339            self.assertEqual(
340                r.Rlocation("protobuf~3.19.2/foo/runfile", "protobuf~3.19.2"),
341                "C:/Actual Path\\protobuf\\runfile",
342            )
343            self.assertEqual(
344                r.Rlocation("protobuf~3.19.2/bar/dir", "protobuf~3.19.2"),
345                "E:\\Actual Path\\Directory",
346            )
347            self.assertEqual(
348                r.Rlocation("protobuf~3.19.2/bar/dir/file", "protobuf~3.19.2"),
349                "E:\\Actual Path\\Directory/file",
350            )
351            self.assertEqual(
352                r.Rlocation(
353                    "protobuf~3.19.2/bar/dir/de eply/nes  ted/fi~le", "protobuf~3.19.2"
354                ),
355                "E:\\Actual Path\\Directory/de eply/nes  ted/fi~le",
356            )
357
358            self.assertEqual(
359                r.Rlocation("config.json", "protobuf~3.19.2"), "/etc/config.json"
360            )
361            self.assertIsNone(r.Rlocation("_main", "protobuf~3.19.2"))
362            self.assertIsNone(r.Rlocation("my_module", "protobuf~3.19.2"))
363            self.assertIsNone(r.Rlocation("protobuf", "protobuf~3.19.2"))
364
365    def testDirectoryBasedRlocation(self):
366        # The _DirectoryBased strategy simply joins the runfiles directory and the
367        # runfile's path on a "/". This strategy does not perform any normalization,
368        # nor does it check that the path exists.
369        r = runfiles.CreateDirectoryBased("foo/bar baz//qux/")
370        self.assertEqual(r.Rlocation("arg"), "foo/bar baz//qux/arg")
371        if RunfilesTest.IsWindows():
372            self.assertEqual(r.Rlocation("c:/foo"), "c:/foo")
373            self.assertEqual(r.Rlocation("c:\\foo"), "c:\\foo")
374        else:
375            self.assertEqual(r.Rlocation("/foo"), "/foo")
376
377    def testDirectoryBasedRlocationWithRepoMappingFromMain(self):
378        with _MockFile(
379            name="_repo_mapping",
380            contents=[
381                "_,config.json,config.json~1.2.3",
382                ",my_module,_main",
383                ",my_protobuf,protobuf~3.19.2",
384                ",my_workspace,_main",
385                "protobuf~3.19.2,config.json,config.json~1.2.3",
386                "protobuf~3.19.2,protobuf,protobuf~3.19.2",
387            ],
388        ) as rm:
389            dir = os.path.dirname(rm.Path())
390            r = runfiles.CreateDirectoryBased(dir)
391
392            self.assertEqual(
393                r.Rlocation("my_module/bar/runfile", ""), dir + "/_main/bar/runfile"
394            )
395            self.assertEqual(
396                r.Rlocation("my_workspace/bar/runfile", ""), dir + "/_main/bar/runfile"
397            )
398            self.assertEqual(
399                r.Rlocation("my_protobuf/foo/runfile", ""),
400                dir + "/protobuf~3.19.2/foo/runfile",
401            )
402            self.assertEqual(
403                r.Rlocation("my_protobuf/bar/dir", ""), dir + "/protobuf~3.19.2/bar/dir"
404            )
405            self.assertEqual(
406                r.Rlocation("my_protobuf/bar/dir/file", ""),
407                dir + "/protobuf~3.19.2/bar/dir/file",
408            )
409            self.assertEqual(
410                r.Rlocation("my_protobuf/bar/dir/de eply/nes ted/fi~le", ""),
411                dir + "/protobuf~3.19.2/bar/dir/de eply/nes ted/fi~le",
412            )
413
414            self.assertEqual(
415                r.Rlocation("protobuf/foo/runfile", ""), dir + "/protobuf/foo/runfile"
416            )
417            self.assertEqual(
418                r.Rlocation("protobuf/bar/dir/dir/de eply/nes ted/fi~le", ""),
419                dir + "/protobuf/bar/dir/dir/de eply/nes ted/fi~le",
420            )
421
422            self.assertEqual(
423                r.Rlocation("_main/bar/runfile", ""), dir + "/_main/bar/runfile"
424            )
425            self.assertEqual(
426                r.Rlocation("protobuf~3.19.2/foo/runfile", ""),
427                dir + "/protobuf~3.19.2/foo/runfile",
428            )
429            self.assertEqual(
430                r.Rlocation("protobuf~3.19.2/bar/dir", ""),
431                dir + "/protobuf~3.19.2/bar/dir",
432            )
433            self.assertEqual(
434                r.Rlocation("protobuf~3.19.2/bar/dir/file", ""),
435                dir + "/protobuf~3.19.2/bar/dir/file",
436            )
437            self.assertEqual(
438                r.Rlocation("protobuf~3.19.2/bar/dir/de eply/nes  ted/fi~le", ""),
439                dir + "/protobuf~3.19.2/bar/dir/de eply/nes  ted/fi~le",
440            )
441
442            self.assertEqual(r.Rlocation("config.json", ""), dir + "/config.json")
443
444    def testDirectoryBasedRlocationWithRepoMappingFromOtherRepo(self):
445        with _MockFile(
446            name="_repo_mapping",
447            contents=[
448                "_,config.json,config.json~1.2.3",
449                ",my_module,_main",
450                ",my_protobuf,protobuf~3.19.2",
451                ",my_workspace,_main",
452                "protobuf~3.19.2,config.json,config.json~1.2.3",
453                "protobuf~3.19.2,protobuf,protobuf~3.19.2",
454            ],
455        ) as rm:
456            dir = os.path.dirname(rm.Path())
457            r = runfiles.CreateDirectoryBased(dir)
458
459            self.assertEqual(
460                r.Rlocation("protobuf/foo/runfile", "protobuf~3.19.2"),
461                dir + "/protobuf~3.19.2/foo/runfile",
462            )
463            self.assertEqual(
464                r.Rlocation("protobuf/bar/dir", "protobuf~3.19.2"),
465                dir + "/protobuf~3.19.2/bar/dir",
466            )
467            self.assertEqual(
468                r.Rlocation("protobuf/bar/dir/file", "protobuf~3.19.2"),
469                dir + "/protobuf~3.19.2/bar/dir/file",
470            )
471            self.assertEqual(
472                r.Rlocation(
473                    "protobuf/bar/dir/de eply/nes  ted/fi~le", "protobuf~3.19.2"
474                ),
475                dir + "/protobuf~3.19.2/bar/dir/de eply/nes  ted/fi~le",
476            )
477
478            self.assertEqual(
479                r.Rlocation("my_module/bar/runfile", "protobuf~3.19.2"),
480                dir + "/my_module/bar/runfile",
481            )
482            self.assertEqual(
483                r.Rlocation(
484                    "my_protobuf/bar/dir/de eply/nes  ted/fi~le", "protobuf~3.19.2"
485                ),
486                dir + "/my_protobuf/bar/dir/de eply/nes  ted/fi~le",
487            )
488
489            self.assertEqual(
490                r.Rlocation("_main/bar/runfile", "protobuf~3.19.2"),
491                dir + "/_main/bar/runfile",
492            )
493            self.assertEqual(
494                r.Rlocation("protobuf~3.19.2/foo/runfile", "protobuf~3.19.2"),
495                dir + "/protobuf~3.19.2/foo/runfile",
496            )
497            self.assertEqual(
498                r.Rlocation("protobuf~3.19.2/bar/dir", "protobuf~3.19.2"),
499                dir + "/protobuf~3.19.2/bar/dir",
500            )
501            self.assertEqual(
502                r.Rlocation("protobuf~3.19.2/bar/dir/file", "protobuf~3.19.2"),
503                dir + "/protobuf~3.19.2/bar/dir/file",
504            )
505            self.assertEqual(
506                r.Rlocation(
507                    "protobuf~3.19.2/bar/dir/de eply/nes  ted/fi~le", "protobuf~3.19.2"
508                ),
509                dir + "/protobuf~3.19.2/bar/dir/de eply/nes  ted/fi~le",
510            )
511
512            self.assertEqual(
513                r.Rlocation("config.json", "protobuf~3.19.2"), dir + "/config.json"
514            )
515
516    def testCurrentRepository(self):
517        # This test assumes that it is running without --enable_bzlmod as the
518        # correct result with Bzlmod would be the empty string - the canonical
519        # name # of the main repository. Without Bzlmod, the main repository is
520        # treated just like any other repository and has the name of its
521        # runfiles directory returned, which coincides with the name specified
522        # in the WORKSPACE file.
523        #
524        # Specify a fake runfiles directory to verify that its value isn't used
525        # by the function.
526        self.assertEqual(
527            runfiles.Create({"RUNFILES_DIR": "whatever"}).CurrentRepository(),
528            "rules_python",
529        )
530
531    @staticmethod
532    def IsWindows():
533        return os.name == "nt"
534
535
536class _MockFile(object):
537    def __init__(self, name=None, contents=None):
538        self._contents = contents or []
539        self._name = name or "x"
540        self._path = None
541
542    def __enter__(self):
543        tmpdir = os.environ.get("TEST_TMPDIR")
544        self._path = os.path.join(tempfile.mkdtemp(dir=tmpdir), self._name)
545        with open(self._path, "wt") as f:
546            f.writelines(l + "\n" for l in self._contents)
547        return self
548
549    def __exit__(self, exc_type, exc_value, traceback):
550        os.remove(self._path)
551        os.rmdir(os.path.dirname(self._path))
552
553    def Path(self):
554        return self._path
555
556
557if __name__ == "__main__":
558    unittest.main()
559