Phillip Smyth pushed to branch issue_640-Build-All at BuildStream / buildstream
Commits:
- 
516e990e
by ctolentino8 at 2018-10-31T11:36:46Z
- 
b8a37a63
by Tristan Van Berkom at 2018-11-01T10:16:25Z
- 
b27b592a
by Benjamin Schubert at 2018-11-01T10:49:57Z
- 
89ace5d7
by Benjamin Schubert at 2018-11-01T11:16:36Z
- 
4cfabce8
by Angelos Evripiotis at 2018-11-01T11:35:02Z
- 
48860aac
by Tristan Van Berkom at 2018-11-01T12:01:04Z
- 
d868b409
by Daniel Silverstone at 2018-11-01T13:40:24Z
- 
7f79b9ce
by Tristan Van Berkom at 2018-11-01T14:25:57Z
- 
4ebf4fd1
by knownexus at 2018-11-02T14:13:44Z
9 changed files:
- NEWS
- buildstream/_frontend/app.py
- buildstream/_frontend/cli.py
- buildstream/_stream.py
- buildstream/_versions.py
- buildstream/_yaml.py
- buildstream/plugins/elements/manual.yaml
- setup.py
- tests/frontend/init.py
Changes:
| ... | ... | @@ -2,6 +2,12 @@ | 
| 2 | 2 |  buildstream 1.3.1
 | 
| 3 | 3 |  =================
 | 
| 4 | 4 |  | 
| 5 | +  o BREAKING CHANGE: The 'manual' element lost its default 'MAKEFLAGS' and 'V'
 | |
| 6 | +    environment variables. There is already a 'make' element with the same
 | |
| 7 | +    variables. Note that this is a breaking change, it will require users to
 | |
| 8 | +    make changes to their .bst files if they are expecting these environment
 | |
| 9 | +    variables to be set.
 | |
| 10 | + | |
| 5 | 11 |    o Failed builds are included in the cache as well.
 | 
| 6 | 12 |      `bst checkout` will provide anything in `%{install-root}`.
 | 
| 7 | 13 |      A build including cached fails will cause any dependant elements
 | 
| ... | ... | @@ -305,7 +305,6 @@ class App(): | 
| 305 | 305 |          directory = self._main_options['directory']
 | 
| 306 | 306 |          directory = os.path.abspath(directory)
 | 
| 307 | 307 |          project_path = os.path.join(directory, 'project.conf')
 | 
| 308 | -        elements_path = os.path.join(directory, element_path)
 | |
| 309 | 308 |  | 
| 310 | 309 |          try:
 | 
| 311 | 310 |              # Abort if the project.conf already exists, unless `--force` was specified in `bst init`
 | 
| ... | ... | @@ -335,6 +334,7 @@ class App(): | 
| 335 | 334 |                  raise AppError("Error creating project directory {}: {}".format(directory, e)) from e
 | 
| 336 | 335 |  | 
| 337 | 336 |              # Create the elements sub-directory if it doesnt exist
 | 
| 337 | +            elements_path = os.path.join(directory, element_path)
 | |
| 338 | 338 |              try:
 | 
| 339 | 339 |                  os.makedirs(elements_path, exist_ok=True)
 | 
| 340 | 340 |              except IOError as e:
 | 
| ... | ... | @@ -305,10 +305,12 @@ def init(app, project_name, format_version, element_path, force): | 
| 305 | 305 |                help="Allow tracking to cross junction boundaries")
 | 
| 306 | 306 |  @click.option('--track-save', default=False, is_flag=True,
 | 
| 307 | 307 |                help="Deprecated: This is ignored")
 | 
| 308 | +@click.option('--world', 'build_world', default=False, is_flag=True,
 | |
| 309 | +              help="Build every element in the project")
 | |
| 308 | 310 |  @click.argument('elements', nargs=-1,
 | 
| 309 | 311 |                  type=click.Path(readable=False))
 | 
| 310 | 312 |  @click.pass_obj
 | 
| 311 | -def build(app, elements, all_, track_, track_save, track_all, track_except, track_cross_junctions):
 | |
| 313 | +def build(app, elements, all_, track_, track_save, track_all, track_except, track_cross_junctions, build_world):
 | |
| 312 | 314 |      """Build elements in a pipeline"""
 | 
| 313 | 315 |  | 
| 314 | 316 |      if (track_except or track_cross_junctions) and not (track_ or track_all):
 | 
| ... | ... | @@ -319,14 +321,13 @@ def build(app, elements, all_, track_, track_save, track_all, track_except, trac | 
| 319 | 321 |      if track_save:
 | 
| 320 | 322 |          click.echo("WARNING: --track-save is deprecated, saving is now unconditional", err=True)
 | 
| 321 | 323 |  | 
| 322 | -    if track_all:
 | |
| 323 | -        track_ = elements
 | |
| 324 | - | |
| 325 | 324 |      with app.initialized(session_name="Build"):
 | 
| 326 | 325 |          app.stream.build(elements,
 | 
| 327 | 326 |                           track_targets=track_,
 | 
| 327 | +                         track_all=track_all,
 | |
| 328 | 328 |                           track_except=track_except,
 | 
| 329 | 329 |                           track_cross_junctions=track_cross_junctions,
 | 
| 330 | +                         build_world=build_world,
 | |
| 330 | 331 |                           build_all=all_)
 | 
| 331 | 332 |  | 
| 332 | 333 |  | 
| ... | ... | @@ -163,15 +163,29 @@ class Stream(): | 
| 163 | 163 |      #
 | 
| 164 | 164 |      def build(self, targets, *,
 | 
| 165 | 165 |                track_targets=None,
 | 
| 166 | +              track_all=False,
 | |
| 166 | 167 |                track_except=None,
 | 
| 167 | 168 |                track_cross_junctions=False,
 | 
| 169 | +              build_world=False,
 | |
| 168 | 170 |                build_all=False):
 | 
| 169 | 171 |  | 
| 170 | -        if build_all:
 | |
| 172 | + | |
| 173 | +        if build_world:
 | |
| 174 | +            for root, _, files in os.walk("elements"):
 | |
| 175 | +                for file in files:
 | |
| 176 | +                    if file.endswith(".bst"):
 | |
| 177 | +                        relDir = os.path.relpath(root, "elements")
 | |
| 178 | +                        relFile = os.path.join(relDir, file).strip("./")
 | |
| 179 | +                        targets = targets + (relFile,)
 | |
| 180 | +            selection = PipelineSelection.PLAN
 | |
| 181 | +        elif build_all:
 | |
| 171 | 182 |              selection = PipelineSelection.ALL
 | 
| 172 | 183 |          else:
 | 
| 173 | 184 |              selection = PipelineSelection.PLAN
 | 
| 174 | 185 |  | 
| 186 | +        if track_all:
 | |
| 187 | +            track_targets = targets
 | |
| 188 | + | |
| 175 | 189 |          elements, track_elements = \
 | 
| 176 | 190 |              self._load(targets, track_targets,
 | 
| 177 | 191 |                         selection=selection, track_selection=PipelineSelection.ALL,
 | 
| ... | ... | @@ -23,7 +23,7 @@ | 
| 23 | 23 |  # This version is bumped whenever enhancements are made
 | 
| 24 | 24 |  # to the `project.conf` format or the core element format.
 | 
| 25 | 25 |  #
 | 
| 26 | -BST_FORMAT_VERSION = 17
 | |
| 26 | +BST_FORMAT_VERSION = 18
 | |
| 27 | 27 |  | 
| 28 | 28 |  | 
| 29 | 29 |  # The base BuildStream artifact version
 | 
| ... | ... | @@ -1049,6 +1049,12 @@ class ChainMap(collections.ChainMap): | 
| 1049 | 1049 |          for key in clearable:
 | 
| 1050 | 1050 |              del self[key]
 | 
| 1051 | 1051 |  | 
| 1052 | +    def get(self, key, default=None):
 | |
| 1053 | +        try:
 | |
| 1054 | +            return self[key]
 | |
| 1055 | +        except KeyError:
 | |
| 1056 | +            return default
 | |
| 1057 | + | |
| 1052 | 1058 |  | 
| 1053 | 1059 |  def node_chain_copy(source):
 | 
| 1054 | 1060 |      copy = ChainMap({}, source)
 | 
| 1 | -# No variables added for the manual element by default, set
 | |
| 2 | -# this if you plan to use make, and the sources cannot handle
 | |
| 3 | -# parallelization.
 | |
| 4 | -#
 | |
| 5 | -# variables:
 | |
| 6 | -#
 | |
| 7 | -#   notparallel: True
 | |
| 8 | - | |
| 9 | 1 |  # Manual build element does not provide any default
 | 
| 10 | 2 |  # build commands
 | 
| 11 | 3 |  config:
 | 
| ... | ... | @@ -28,14 +20,3 @@ config: | 
| 28 | 20 |    strip-commands:
 | 
| 29 | 21 |    - |
 | 
| 30 | 22 |      %{strip-binaries} | 
| 31 | - | |
| 32 | -# Use max-jobs CPUs for building and enable verbosity
 | |
| 33 | -environment:
 | |
| 34 | -  MAKEFLAGS: -j%{max-jobs}
 | |
| 35 | -  V: 1
 | |
| 36 | - | |
| 37 | -# And dont consider MAKEFLAGS or V as something which may
 | |
| 38 | -# affect build output.
 | |
| 39 | -environment-nocache:
 | |
| 40 | -- MAKEFLAGS
 | |
| 41 | -- V | 
| ... | ... | @@ -39,6 +39,7 @@ if sys.version_info[0] != REQUIRED_PYTHON_MAJOR or sys.version_info[1] < REQUIRE | 
| 39 | 39 |  try:
 | 
| 40 | 40 |      from setuptools import setup, find_packages, Command
 | 
| 41 | 41 |      from setuptools.command.easy_install import ScriptWriter
 | 
| 42 | +    from setuptools.command.test import test as TestCommand
 | |
| 42 | 43 |  except ImportError:
 | 
| 43 | 44 |      print("BuildStream requires setuptools in order to build. Install it using"
 | 
| 44 | 45 |            " your package manager (usually python3-setuptools) or via pip (pip3"
 | 
| ... | ... | @@ -219,9 +220,48 @@ class BuildGRPC(Command): | 
| 219 | 220 |                          f.write(code)
 | 
| 220 | 221 |  | 
| 221 | 222 |  | 
| 223 | +#####################################################
 | |
| 224 | +#                   Pytest command                  #
 | |
| 225 | +#####################################################
 | |
| 226 | +class PyTest(TestCommand):
 | |
| 227 | +    """Defines a pytest command class to run tests from setup.py"""
 | |
| 228 | + | |
| 229 | +    user_options = TestCommand.user_options + [
 | |
| 230 | +        ("addopts=", None, "Arguments to pass to pytest"),
 | |
| 231 | +        ('index-url=''build_grpc': BuildGRPC,
 | |
| 264 | +        'pytest': PyTest,
 | |
| 225 | 265 |      }
 | 
| 226 | 266 |      cmdclass.update(versioneer.get_cmdclass())
 | 
| 227 | 267 |      return cmdclass
 | 
| ... | ... | @@ -305,6 +345,5 @@ setup(name='BuildStream', | 
| 305 | 345 |            'grpcio >= 1.10',
 | 
| 306 | 346 |        ],
 | 
| 307 | 347 |        entry_points=bst_install_entry_points,
 | 
| 308 | -      setup_requires=['pytest-runner'],
 | |
| 309 | 348 |        tests_require=dev_requires,
 | 
| 310 | 349 |        zip_safe=False) | 
| ... | ... | @@ -3,6 +3,7 @@ import pytest | 
| 3 | 3 |  from tests.testutils import cli
 | 
| 4 | 4 |  | 
| 5 | 5 |  from buildstream import _yaml
 | 
| 6 | +from buildstream._frontend.app import App
 | |
| 6 | 7 |  from buildstream._exceptions import ErrorDomain, LoadErrorReason
 | 
| 7 | 8 |  from buildstream._versions import BST_FORMAT_VERSION
 | 
| 8 | 9 |  | 
| ... | ... | @@ -98,3 +99,34 @@ def test_bad_element_path(cli, tmpdir, element_path): | 
| 98 | 99 |          'init', '--project-name', 'foo', '--element-path', element_path
 | 
| 99 | 100 |      ])
 | 
| 100 | 101 |      result.assert_main_error(ErrorDomain.APP, 'invalid-element-path')
 | 
| 102 | + | |
| 103 | + | |
| 104 | +@pytest.mark.parametrize("element_path", [('foo'), ('foo/bar')])
 | |
| 105 | +def test_element_path_interactive(cli, tmp_path, monkeypatch, element_path):
 | |
| 106 | +    project = tmp_path
 | |
| 107 | +    project_conf_path = project.joinpath('project.conf')
 | |
| 108 | + | |
| 109 | +    class DummyInteractiveApp(App):
 | |
| 110 | +        def __init__(self, *args, **kwargs):
 | |
| 111 | +            super().__init__(*args, **kwargs)
 | |
| 112 | +            self.interactive = True
 | |
| 113 | + | |
| 114 | +        @classmethod
 | |
| 115 | +        def create(cls, *args, **kwargs):
 | |
| 116 | +            return DummyInteractiveApp(*args, **kwargs)
 | |
| 117 | + | |
| 118 | +        def _init_project_interactive(self, *args, **kwargs):
 | |
| 119 | +            return ('project_name', '0', element_path)
 | |
| 120 | + | |
| 121 | +    monkeypatch.setattr(App, 'create', DummyInteractiveApp.create)
 | |
| 122 | + | |
| 123 | +    result = cli.run(project=str(project), args=['init'])
 | |
| 124 | +    result.assert_success()
 | |
| 125 | + | |
| 126 | +    full_element_path = project.joinpath(element_path)
 | |
| 127 | +    assert full_element_path.exists()
 | |
| 128 | + | |
| 129 | +    project_conf = _yaml.load(str(project_conf_path))
 | |
| 130 | +    assert project_conf['name'] == 'project_name'
 | |
| 131 | +    assert project_conf['format-version'] == '0'
 | |
| 132 | +    assert project_conf['element-path'] == element_path | 
