alibuild 1.17.19__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (74) hide show
  1. alibuild-1.17.19.data/scripts/aliBuild +137 -0
  2. alibuild-1.17.19.data/scripts/aliDeps +7 -0
  3. alibuild-1.17.19.data/scripts/aliDoctor +7 -0
  4. alibuild-1.17.19.data/scripts/alienv +344 -0
  5. alibuild-1.17.19.data/scripts/pb +7 -0
  6. alibuild-1.17.19.dist-info/METADATA +78 -0
  7. alibuild-1.17.19.dist-info/RECORD +74 -0
  8. alibuild-1.17.19.dist-info/WHEEL +5 -0
  9. alibuild-1.17.19.dist-info/licenses/LICENSE.md +674 -0
  10. alibuild-1.17.19.dist-info/top_level.txt +5 -0
  11. alibuild_helpers/__init__.py +21 -0
  12. alibuild_helpers/_version.py +21 -0
  13. alibuild_helpers/analytics.py +120 -0
  14. alibuild_helpers/args.py +493 -0
  15. alibuild_helpers/build.py +1209 -0
  16. alibuild_helpers/build_template.sh +314 -0
  17. alibuild_helpers/clean.py +83 -0
  18. alibuild_helpers/cmd.py +154 -0
  19. alibuild_helpers/deps.py +116 -0
  20. alibuild_helpers/doctor.py +195 -0
  21. alibuild_helpers/git.py +104 -0
  22. alibuild_helpers/init.py +103 -0
  23. alibuild_helpers/log.py +132 -0
  24. alibuild_helpers/scm.py +31 -0
  25. alibuild_helpers/sl.py +62 -0
  26. alibuild_helpers/sync.py +693 -0
  27. alibuild_helpers/templating_plugin.py +18 -0
  28. alibuild_helpers/utilities.py +662 -0
  29. alibuild_helpers/workarea.py +179 -0
  30. debian/changelog +11 -0
  31. debian/compat +1 -0
  32. debian/control +14 -0
  33. debian/copyright +10 -0
  34. debian/files +1 -0
  35. debian/rules +7 -0
  36. docs/README.md +1 -0
  37. docs/SUPPORT +3 -0
  38. docs/docs/alice_logo.png +0 -0
  39. docs/docs/deps.png +0 -0
  40. docs/docs/index.md +75 -0
  41. docs/docs/quick.md +89 -0
  42. docs/docs/reference.md +430 -0
  43. docs/docs/stylesheets/extra.css +9 -0
  44. docs/docs/troubleshooting.md +346 -0
  45. docs/docs/user.md +413 -0
  46. docs/mkdocs.yml +37 -0
  47. templates/alibuild_to_please.jnj +63 -0
  48. tests/test_analytics.py +42 -0
  49. tests/test_args.py +119 -0
  50. tests/test_build.py +426 -0
  51. tests/test_clean.py +154 -0
  52. tests/test_cmd.py +73 -0
  53. tests/test_deps.py +79 -0
  54. tests/test_doctor.py +128 -0
  55. tests/test_git.py +48 -0
  56. tests/test_hashing.py +67 -0
  57. tests/test_init.py +103 -0
  58. tests/test_log.py +50 -0
  59. tests/test_packagelist.py +235 -0
  60. tests/test_parseRecipe.py +132 -0
  61. tests/test_sync.py +332 -0
  62. tests/test_utilities.py +383 -0
  63. tests/test_workarea.py +101 -0
  64. tests/testdist/broken1.sh +1 -0
  65. tests/testdist/broken2.sh +1 -0
  66. tests/testdist/broken3.sh +3 -0
  67. tests/testdist/broken4.sh +2 -0
  68. tests/testdist/broken5.sh +2 -0
  69. tests/testdist/broken6.sh +2 -0
  70. tests/testdist/broken7.sh +5 -0
  71. tests/testdist/clobber-initdotsh.sh +4 -0
  72. tests/testdist/defaults-o2.sh +10 -0
  73. tests/testdist/delete-etc.sh +4 -0
  74. tests/testdist/tracking-env.sh +6 -0
@@ -0,0 +1,235 @@
1
+ from textwrap import dedent
2
+ import unittest
3
+ from unittest import mock
4
+ from unittest.mock import patch
5
+ import os.path
6
+ import tempfile
7
+
8
+ from alibuild_helpers.cmd import getstatusoutput
9
+ from alibuild_helpers.utilities import getPackageList
10
+
11
+
12
+ RECIPES = {
13
+ "CONFIG_DIR/defaults-release.sh": dedent("""\
14
+ package: defaults-release
15
+ version: v1
16
+ force_rebuild: false
17
+ ---
18
+ """),
19
+ "CONFIG_DIR/disable.sh": dedent("""\
20
+ package: disable
21
+ version: v1
22
+ prefer_system: '.*'
23
+ prefer_system_check: 'true'
24
+ ---
25
+ """),
26
+ "CONFIG_DIR/with-replacement.sh": dedent("""\
27
+ package: with-replacement
28
+ version: v1
29
+ prefer_system: '.*'
30
+ prefer_system_check: |
31
+ echo 'alibuild_system_replace: replacement'
32
+ prefer_system_replacement_specs:
33
+ replacement:
34
+ env:
35
+ SENTINEL_VAR: magic
36
+ ---
37
+ """),
38
+ "CONFIG_DIR/with-replacement-recipe.sh": dedent("""\
39
+ package: with-replacement-recipe
40
+ version: v1
41
+ prefer_system: '.*'
42
+ prefer_system_check: |
43
+ echo 'alibuild_system_replace: replacement'
44
+ prefer_system_replacement_specs:
45
+ replacement:
46
+ recipe: 'true'
47
+ ---
48
+ """),
49
+ "CONFIG_DIR/missing-spec.sh": dedent("""\
50
+ package: missing-spec
51
+ version: v1
52
+ prefer_system: '.*'
53
+ prefer_system_check: |
54
+ echo 'alibuild_system_replace: missing_tag'
55
+ prefer_system_replacement_specs: {}
56
+ ---
57
+ """),
58
+ "CONFIG_DIR/sentinel-command.sh": dedent("""\
59
+ package: sentinel-command
60
+ version: v1
61
+ prefer_system: '.*'
62
+ prefer_system_check: |
63
+ : magic sentinel command
64
+ ---
65
+ """),
66
+ "CONFIG_DIR/force-rebuild.sh": dedent("""\
67
+ package: force-rebuild
68
+ version: v1
69
+ force_rebuild: true
70
+ ---
71
+ """),
72
+ "CONFIG_DIR/dirty_prefer_system_check.sh": dedent("""\
73
+ package: dirty_prefer_system_check
74
+ version: v1
75
+ prefer_system: .*
76
+ prefer_system_check: |
77
+ pwd > HEREE
78
+ exit 0
79
+ ---
80
+ """),
81
+ }
82
+
83
+ class MockReader:
84
+ def __init__(self, url: str, dist=None):
85
+ self._contents = RECIPES[url]
86
+ self.url = "mock://" + url
87
+
88
+ def __call__(self):
89
+ return self._contents
90
+
91
+
92
+
93
+ def getPackageListWithDefaults(packages, force_rebuild=()):
94
+ specs = {} # getPackageList will mutate this
95
+ def performPreferCheckWithTempDir(pkg, cmd):
96
+ with tempfile.TemporaryDirectory(prefix=f"alibuild_prefer_check_{pkg['package']}_") as temp_dir:
97
+ return getstatusoutput(cmd, cwd=temp_dir)
98
+ return_values = getPackageList(
99
+ packages=packages,
100
+ specs=specs,
101
+ configDir="CONFIG_DIR",
102
+ # Make sure getPackageList considers prefer_system_check.
103
+ # (Even with preferSystem=False + noSystem=None, it is sufficient
104
+ # if the prefer_system regex matches the architecture.)
105
+ preferSystem=True,
106
+ noSystem=None,
107
+ architecture="ARCH",
108
+ disable=[],
109
+ defaults="release",
110
+ # Mock recipes just run "echo" or ":", so this is safe.
111
+ performPreferCheck=performPreferCheckWithTempDir,
112
+ performRequirementCheck=performPreferCheckWithTempDir,
113
+ performValidateDefaults=lambda spec: (True, "", ["release"]),
114
+ overrides={"defaults-release": {}},
115
+ taps={},
116
+ log=lambda *_: None,
117
+ force_rebuild=force_rebuild,
118
+ )
119
+ return (specs, *return_values)
120
+
121
+
122
+ @mock.patch("alibuild_helpers.utilities.getRecipeReader", new=MockReader)
123
+ class ReplacementTestCase(unittest.TestCase):
124
+ """Test that system package replacements are working."""
125
+
126
+ def test_disable(self):
127
+ """Check that not specifying any replacement disables the package.
128
+
129
+ This is was the only available behaviour in previous aliBuild versions
130
+ and must be preserved for backward compatibility.
131
+ """
132
+ def fake_exists(n):
133
+ return n in RECIPES.keys()
134
+ with patch.object(os.path, "exists", fake_exists):
135
+ specs, systemPkgs, ownPkgs, failedReqs, validDefaults = \
136
+ getPackageListWithDefaults(["disable"])
137
+ self.assertIn("disable", systemPkgs)
138
+ self.assertNotIn("disable", ownPkgs)
139
+ self.assertNotIn("disable", specs)
140
+
141
+ def test_replacement_given(self):
142
+ """Check that specifying a replacement spec means it is used.
143
+
144
+ This also checks that if no recipe is given, we report the package as
145
+ a system package to the user.
146
+ """
147
+ def fake_exists(n):
148
+ return n in RECIPES.keys()
149
+ with patch.object(os.path, "exists", fake_exists):
150
+ specs, systemPkgs, ownPkgs, failedReqs, validDefaults = \
151
+ getPackageListWithDefaults(["with-replacement"])
152
+ self.assertIn("with-replacement", specs)
153
+ self.assertEqual(specs["with-replacement"]["env"]["SENTINEL_VAR"], "magic")
154
+ # Make sure nothing is run by default.
155
+ self.assertEqual(specs["with-replacement"]["recipe"], "")
156
+ # If the replacement spec has no recipe, report to the user that we're
157
+ # taking the package from the system.
158
+ self.assertIn("with-replacement", systemPkgs)
159
+ self.assertNotIn("with-replacement", ownPkgs)
160
+
161
+ def test_replacement_recipe_given(self) -> None:
162
+ """Check that specifying a replacement recipe means it is used.
163
+
164
+ Also check that we report to the user that a package will be compiled
165
+ when a replacement recipe is given.
166
+ """
167
+ def fake_exists(n):
168
+ return n in RECIPES.keys()
169
+ with patch.object(os.path, "exists", fake_exists):
170
+ specs, systemPkgs, ownPkgs, failedReqs, validDefaults = \
171
+ getPackageListWithDefaults(["with-replacement-recipe"])
172
+ self.assertIn("with-replacement-recipe", specs)
173
+ self.assertIn("recipe", specs["with-replacement-recipe"])
174
+ self.assertEqual("true", specs["with-replacement-recipe"]["recipe"])
175
+ # If the replacement spec has a recipe, report to the user that we're
176
+ # compiling the package.
177
+ self.assertNotIn("with-replacement-recipe", systemPkgs)
178
+ self.assertIn("with-replacement-recipe", ownPkgs)
179
+
180
+ @mock.patch("alibuild_helpers.utilities.warning")
181
+ def test_missing_replacement_spec(self, mock_warning) -> None:
182
+ """Check a warning is displayed when the replacement spec is not found."""
183
+ warning_msg = "falling back to building the package ourselves"
184
+ warning_exists = False
185
+ def fake_exists(n):
186
+ return n in RECIPES.keys()
187
+ with patch.object(os.path, "exists", fake_exists):
188
+ def side_effect(msg, *args, **kwargs):
189
+ nonlocal warning_exists
190
+ if warning_msg in str(msg):
191
+ warning_exists = True
192
+ mock_warning.side_effect = side_effect
193
+ specs, systemPkgs, ownPkgs, failedReqs, validDefaults = \
194
+ getPackageListWithDefaults(["missing-spec"])
195
+ self.assertTrue(warning_exists)
196
+
197
+ def test_dirty_system_check(self) -> None:
198
+ """Check that prefer_system_check runs in isolation and doesn't create files in cwd."""
199
+ def fake_exists(n):
200
+ return n in RECIPES.keys()
201
+ with patch.object(os.path, "exists", fake_exists):
202
+ getPackageListWithDefaults(["dirty_prefer_system_check"])
203
+ # can't use os.path.exists() ourselves, as we just mocked it
204
+ self.assertFalse("HEREE" in os.listdir())
205
+
206
+
207
+ @mock.patch("alibuild_helpers.utilities.getRecipeReader", new=MockReader)
208
+ class ForceRebuildTestCase(unittest.TestCase):
209
+ """Test that force_rebuild keys are applied properly."""
210
+
211
+ def test_force_rebuild_recipe(self) -> None:
212
+ """If the recipe specifies force_rebuild, it must be applied."""
213
+ def fake_exists(n):
214
+ return n in RECIPES.keys()
215
+ with patch.object(os.path, "exists", fake_exists):
216
+ specs, _, _, _, _ = getPackageListWithDefaults(["force-rebuild"])
217
+ self.assertTrue(specs["force-rebuild"]["force_rebuild"])
218
+ self.assertFalse(specs["defaults-release"]["force_rebuild"])
219
+
220
+ def test_force_rebuild_command_line(self) -> None:
221
+ """The --force-rebuild option must take precedence, if given."""
222
+ def fake_exists(n):
223
+ return n in RECIPES.keys()
224
+ with patch.object(os.path, "exists", fake_exists):
225
+ specs, _, _, _, _ = getPackageListWithDefaults(
226
+ ["force-rebuild"], force_rebuild=["defaults-release", "force-rebuild"],
227
+ )
228
+ self.assertTrue(specs["force-rebuild"]["force_rebuild"])
229
+ self.assertTrue(specs["defaults-release"]["force_rebuild"])
230
+
231
+
232
+
233
+
234
+ if __name__ == '__main__':
235
+ unittest.main()
@@ -0,0 +1,132 @@
1
+ import unittest
2
+ from alibuild_helpers.utilities import parseRecipe, getRecipeReader, parseDefaults
3
+ from alibuild_helpers.utilities import FileReader, GitReader
4
+ from alibuild_helpers.utilities import validateDefaults
5
+ from collections import OrderedDict
6
+
7
+ TEST1="""package: foo
8
+ version: bar
9
+ ---
10
+ """
11
+
12
+ TEST_BROKEN_1 = "broken"
13
+ TEST_BROKEN_2 = "---"
14
+ TEST_BROKEN_3 = """gfooo:
15
+ - :
16
+ ---
17
+ """
18
+ TEST_BROKEN_4 = """broken
19
+ ---
20
+ """
21
+
22
+ TEST_BROKEN_5 = """tag: foo
23
+ ---
24
+ """
25
+
26
+ TEST_BROKEN_6 = """tag: "foo
27
+ ---
28
+ """
29
+
30
+ ERROR_MSG_3 = """Unable to parse test_broken_3.sh
31
+ while parsing a block mapping
32
+ expected <block end>, but found ':'
33
+ in "<unicode string>", line 2, column 6:
34
+ - :
35
+ ^"""
36
+
37
+ ERROR_MSG_4 = """Malformed header for test_broken_4.sh
38
+ Not a YAML key / value."""
39
+
40
+ ERROR_MSG_5 = """Malformed header for test_broken_5.sh
41
+ Missing package field in header."""
42
+
43
+ ERROR_MSG_6 = """Unable to parse test_broken_6.sh
44
+ while scanning a quoted scalar
45
+ in "<unicode string>", line 1, column 6:
46
+ tag: "foo
47
+ ^
48
+ found unexpected end of stream
49
+ in "<unicode string>", line 2, column 1:
50
+
51
+ ^"""
52
+
53
+ class Recoder(object):
54
+ def __init__(self) -> None:
55
+ self.buffer = ""
56
+ def __call__(self, s, *a) -> None:
57
+ self.buffer += s % a
58
+
59
+ class BufferReader(object):
60
+ def __init__(self, filename, recipe) -> None:
61
+ self.url = filename
62
+ self.buffer = recipe
63
+ def __call__(self):
64
+ if type(self.buffer) == bytes:
65
+ return self.buffer.decode()
66
+ else:
67
+ return self.buffer
68
+
69
+ class TestRecipes(unittest.TestCase):
70
+ def test_recipes(self) -> None:
71
+ err, meta, body = parseRecipe(BufferReader("test1.sh", TEST1))
72
+ self.assertEqual(err, None)
73
+ self.assertEqual(meta["package"], "foo")
74
+ self.assertEqual(meta["version"], "bar")
75
+ err, meta, body = parseRecipe(BufferReader("test_broken_1.sh", TEST_BROKEN_1))
76
+ self.assertEqual(err, "Unable to parse test_broken_1.sh. Header missing.")
77
+ err, meta, body = parseRecipe(BufferReader("test_broken_2.sh", TEST_BROKEN_2))
78
+ self.assertEqual(err, "Malformed header for test_broken_2.sh\nEmpty recipe.")
79
+ self.assertTrue(not meta and not body)
80
+ err, meta, body = parseRecipe(BufferReader("test_broken_3.sh", TEST_BROKEN_3))
81
+ self.assertEqual(err.encode("ascii"), ERROR_MSG_3.encode("ascii"))
82
+ self.assertEqual(meta, None)
83
+ self.assertEqual(body.strip(), "")
84
+ err, meta, body = parseRecipe(BufferReader("test_broken_4.sh", TEST_BROKEN_4))
85
+ self.assertEqual(err, ERROR_MSG_4)
86
+ err, meta, body = parseRecipe(BufferReader("test_broken_5.sh", TEST_BROKEN_5))
87
+ self.assertEqual(err, ERROR_MSG_5)
88
+ err, meta, body = parseRecipe(BufferReader("test_broken_6.sh", TEST_BROKEN_6))
89
+ self.assertEqual(err.strip(), ERROR_MSG_6.strip())
90
+
91
+ def test_getRecipeReader(self) -> None:
92
+ f = getRecipeReader("foo")
93
+ self.assertEqual(type(f), FileReader)
94
+ f = getRecipeReader("dist:foo@master")
95
+ self.assertEqual(type(f), FileReader)
96
+ f = getRecipeReader("dist:foo@master", "alidist")
97
+ self.assertEqual(type(f), GitReader)
98
+
99
+ def test_parseDefaults(self) -> None:
100
+ disable = ["bar"]
101
+ err, overrides, taps = parseDefaults(disable,
102
+ lambda: ({ "disable": "foo",
103
+ "overrides": OrderedDict({"ROOT@master": {"requires": "GCC"}})},
104
+ ""),
105
+ Recoder())
106
+ self.assertEqual(disable, ["bar", "foo"])
107
+ self.assertEqual(overrides, {'defaults-release': {}, 'root': {'requires': 'GCC'}})
108
+ self.assertEqual(taps, {'root': 'dist:ROOT@master'})
109
+
110
+ def test_validateDefault(self) -> None:
111
+ ok, out, validDefaults = validateDefaults({"something": True}, "release")
112
+ self.assertEqual(ok, True)
113
+ ok, out, validDefaults = validateDefaults({"package": "foo","valid_defaults": ["o2", "o2-dataflow"]}, "release")
114
+ self.assertEqual(ok, False)
115
+ self.assertEqual(out, 'Cannot compile foo with `release\' default. Valid defaults are\n - o2\n - o2-dataflow')
116
+ ok, out, validDefaults = validateDefaults({"package": "foo","valid_defaults": ["o2", "o2-dataflow"]}, "o2")
117
+ self.assertEqual(ok, True)
118
+ ok, out, validDefaults = validateDefaults({"package": "foo","valid_defaults": "o2-dataflow"}, "o2")
119
+ self.assertEqual(ok, False)
120
+ self.assertEqual(validDefaults, ["o2-dataflow"])
121
+ ok, out, validDefaults = validateDefaults({"package": "foo","valid_defaults": "o2"}, "o2")
122
+ self.assertEqual(ok, True)
123
+ ok, out, validDefaults = validateDefaults({"package": "foo","valid_defaults": 1}, "o2")
124
+ self.assertEqual(ok, False)
125
+ self.assertEqual(out, 'valid_defaults needs to be a string or a list of strings. Found [1].')
126
+ ok, out, validDefaults = validateDefaults({"package": "foo", "valid_defaults": {}}, "o2")
127
+ self.assertEqual(ok, False)
128
+ self.assertEqual(out, 'valid_defaults needs to be a string or a list of strings. Found [{}].')
129
+
130
+ if __name__ == '__main__':
131
+ unittest.main()
132
+