Exemplo n.º 1
0
    def zephyr_manifest(self):
        # load the upstream manifest. the west.manifest APIs guarantee
        # in this case that its project hierarchy is rooted in the NCS
        # directory.

        z_project = self.manifest.get_projects(['zephyr'],
                                               allow_paths=False,
                                               only_cloned=True)[0]
        cp = z_project.git(f'show {self.zephyr_rev}:west.yml',
                           capture_stdout=True,
                           check=True)
        z_west_yml = cp.stdout.decode('utf-8')
        try:
            # The topdir kwarg was added in a pre-release west, which
            # is required to use this file. The latest stable (0.6.3)
            # doesn't have it, so pylint is failing with a false error
            # report here. Turn it off for now; this can be removed
            # when west 0.7 is out.
            #
            # pylint: disable=unexpected-keyword-arg
            return Manifest.from_data(source_data=yaml.safe_load(z_west_yml),
                                      topdir=self.topdir)
        except MalformedManifest:
            log.die(f"can't load zephyr manifest; file {z_west_yml} "
                    "is malformed")
Exemplo n.º 2
0
def test_sections():
    # We no longer validate the west section, so things that would
    # once have been schema errors shouldn't matter.

    content_wrong_west = '''\
    west:
      url: https://example.com
      revision: abranch
      wrongfield: avalue
    manifest:
      remotes:
        - name: testremote
          url-base: https://example.com
      projects:
        - name: testproject
          remote: testremote
          path: sub/directory
    '''
    with patch('west.util.west_topdir',
               return_value=os.path.realpath('/west_top')):
        # Parsing manifest only, no exception raised
        manifest = Manifest.from_data(yaml.safe_load(content_wrong_west))
    assert manifest.projects[1].path == 'sub' + os.path.sep + 'directory'
    assert manifest.projects[1].abspath == \
        os.path.realpath('/west_top/sub/directory')
Exemplo n.º 3
0
def test_ignore_west_section():
    # We no longer validate the west section, so things that would
    # once have been schema errors shouldn't be anymore. Projects
    # should still work as expected regardless of what's in there.

    content_wrong_west = '''\
    west:
      url: https://example.com
      revision: abranch
      wrongfield: avalue
    manifest:
      remotes:
        - name: testremote
          url-base: https://example.com
      projects:
        - name: testproject
          remote: testremote
          path: sub/directory
    '''
    # Parsing manifest only, no exception raised
    manifest = Manifest.from_data(yaml.safe_load(content_wrong_west),
                                  topdir='/west_top')
    p1 = manifest.projects[1]
    assert PurePath(p1.path) == PurePath('sub', 'directory')
    assert PurePath(p1.abspath) == PurePath('/west_top/sub/directory')
Exemplo n.º 4
0
def test_sections():
    # Projects must be able to override their default paths.
    content_wrong_west = '''\
    west:
      url: https://example.com
      revision: abranch
      wrongfield: avalue
    manifest:
      remotes:
        - name: testremote
          url-base: https://example.com
      projects:
        - name: testproject
          remote: testremote
          path: sub/directory
    '''
    with patch('west.util.west_topdir',
               return_value=os.path.realpath('/west_top')):
        # Parsing manifest only, no exception raised
        manifest = Manifest.from_data(yaml.safe_load(content_wrong_west),
                                      sections=['manifest'])
    assert manifest.projects[1].path == 'sub' + os.path.sep + 'directory'
    assert manifest.projects[1].abspath == \
        os.path.realpath('/west_top/sub/directory')
    content_wrong_manifest = '''\
    west:
      url: https://example.com
      revision: abranch
    manifest:
      remotes:
        - name: testremote
          url-base: https://example.com
      projects:
        - name: testproject
          remote: testremote
          path: sub/directory
    '''
    with patch('west.util.west_topdir',
               return_value=os.path.realpath('/west_top')):
        # Parsing west section only, no exception raised
        manifest = Manifest.from_data(yaml.safe_load(content_wrong_manifest),
                                      sections=['west'])
    assert manifest.west_project.url == 'https://example.com'
    assert manifest.west_project.revision == 'abranch'
Exemplo n.º 5
0
def test_default_clone_depth(config_file_project_setup):
    # Defaults and clone depth should work as in this example.
    content = '''\
    manifest:
      defaults:
        remote: testremote1
        revision: defaultrev

      remotes:
        - name: testremote1
          url-base: https://example1.com
        - name: testremote2
          url-base: https://example2.com

      projects:
        - name: testproject1
        - name: testproject2
          remote: testremote2
          revision: rev
          clone-depth: 1
    '''
    r1 = Remote('testremote1', 'https://example1.com')
    r2 = Remote('testremote2', 'https://example2.com')
    d = Defaults(remote=r1, revision='defaultrev')

    with patch('west.util.west_topdir', return_value='/west_top'):
        manifest = Manifest.from_data(yaml.safe_load(content))

        expected = [
            ManifestProject(path='manifestproject'),
            Project('testproject1',
                    d,
                    path='testproject1',
                    clone_depth=None,
                    revision=d.revision,
                    remote=r1),
            Project('testproject2',
                    d,
                    path='testproject2',
                    clone_depth=1,
                    revision='rev',
                    remote=r2)
        ]

    # Check that default attributes match.
    assert manifest.defaults.remote == d.remote
    assert manifest.defaults.revision == d.revision

    # Check the remotes are as expected.
    assert list(manifest.remotes) == [r1, r2]

    # Check that the projects are as expected.
    for p, e in zip(manifest.projects, expected):
        deep_eq_check(p, e)
    assert all(p.abspath == os.path.realpath(os.path.join('/west_top', p.path))
               for p in manifest.projects)
Exemplo n.º 6
0
def test_project_named_west():
    # A project named west is allowed now, even though it was once an error.

    content = '''\
    manifest:
      projects:
        - name: west
          url: https://foo.com
    '''
    manifest = Manifest.from_data(yaml.safe_load(content))
    assert manifest.projects[1].name == 'west'
Exemplo n.º 7
0
def test_no_remote_ok(west_topdir):
    # remotes isn't required if projects are specified by URL.

    content = '''\
    manifest:
      projects:
        - name: testproject
          url: https://example.com/my-project
    '''
    manifest = Manifest.from_data(yaml.safe_load(content))
    assert manifest.projects[1].url == 'https://example.com/my-project'
Exemplo n.º 8
0
def test_get_projects_unknown():
    content = '''\
    manifest:
      projects:
        - name: foo
          url: https://foo.com
    '''
    with patch('west.util.west_topdir', return_value='/west_top'):
        manifest = Manifest.from_data(yaml.safe_load(content))
        with pytest.raises(ValueError):
            manifest.get_projects(['unknown'])
Exemplo n.º 9
0
def test_default_clone_depth():
    # Defaults and clone depth should work as in this example.
    content = '''\
    manifest:
      defaults:
        remote: testremote1
        revision: defaultrev

      remotes:
        - name: testremote1
          url-base: https://example1.com
        - name: testremote2
          url-base: https://example2.com

      projects:
        - name: testproject1
        - name: testproject2
          remote: testremote2
          revision: rev
          clone-depth: 1
    '''
    r1 = Remote('testremote1', 'https://example1.com')
    r2 = Remote('testremote2', 'https://example2.com')
    d = Defaults(remote=r1, revision='defaultrev')

    manifest = Manifest.from_data(yaml.safe_load(content))

    expected = [
        Project('testproject1',
                d,
                path='testproject1',
                clone_depth=None,
                revision=d.revision,
                remote=r1),
        Project('testproject2',
                d,
                path='testproject2',
                clone_depth=1,
                revision='rev',
                remote=r2)
    ]

    # Check that default attributes match.
    assert manifest.defaults.remote == d.remote
    assert manifest.defaults.revision == d.revision

    # Check the remotes are as expected.
    assert list(manifest.remotes) == [r1, r2]

    # Check that the projects are as expected.
    for p, e in zip(manifest.projects[1:], expected):
        check_proj_consistency(p, e)
Exemplo n.º 10
0
def test_project_west_commands():
    # Projects may specify subdirectories containing west commands.

    content = '''\
    manifest:
      projects:
        - name: zephyr
          url: https://foo.com
          west-commands: some-path/west-commands.yml
    '''
    manifest = Manifest.from_data(yaml.safe_load(content))
    assert len(manifest.projects) == 2
    assert manifest.projects[1].west_commands == 'some-path/west-commands.yml'
Exemplo n.º 11
0
def test_get_projects_unknown():
    # Attempting to get an unknown project is an error.
    # TODO: add more testing for get_projects().

    content = '''\
    manifest:
      projects:
        - name: foo
          url: https://foo.com
    '''
    manifest = Manifest.from_data(yaml.safe_load(content))
    with pytest.raises(ValueError):
        manifest.get_projects(['unknown'])
Exemplo n.º 12
0
def test_self_tag(project_setup):
    # Manifests with self tag reference.
    content = '''\
    manifest:
      remotes:
        - name: testremote1
          url-base: https://example1.com
        - name: testremote2
          url-base: https://example2.com

      projects:
        - name: testproject1
          remote: testremote1
          revision: rev1
        - name: testproject2
          remote: testremote2

      self:
        path: mainproject
    '''
    r1 = Remote('testremote1', 'https://example1.com')
    r2 = Remote('testremote2', 'https://example2.com')

    with patch('west.util.west_topdir', return_value='/west_top'):
        manifest = Manifest.from_data(yaml.safe_load(content))

        expected = [
            ManifestProject(path='mainproject'),
            Project('testproject1',
                    None,
                    path='testproject1',
                    clone_depth=None,
                    revision='rev1',
                    remote=r1),
            Project('testproject2',
                    None,
                    path='testproject2',
                    clone_depth=None,
                    revision='master',
                    remote=r2)
        ]

    # Check the remotes are as expected.
    assert list(manifest.remotes) == [r1, r2]

    # Check the projects are as expected.
    for p, e in zip(manifest.projects, expected):
        deep_eq_check(p, e)
    assert all(p.abspath == os.path.realpath(os.path.join('/west_top', p.path))
               for p in manifest.projects)
Exemplo n.º 13
0
def manifest_from_url(token, url):

    log(f'Creating manifest from {url}')

    # Download manifest file
    header = {'Authorization': f'token {token}'}
    req = requests.get(url=url, headers=header)
    try:
        manifest = Manifest.from_data(req.content.decode(),
                                      import_flags=ImportFlag.IGNORE_PROJECTS)
    except MalformedManifest as e:
        die(f'Failed to parse manifest from {url}: {e}')

    return manifest
Exemplo n.º 14
0
def test_self_tag():
    # Manifests may contain a self section describing their behavior.
    # It should work with multiple projects and remotes as expected.

    content = '''\
    manifest:
      remotes:
        - name: testremote1
          url-base: https://example1.com
        - name: testremote2
          url-base: https://example2.com

      projects:
        - name: testproject1
          remote: testremote1
          revision: rev1
        - name: testproject2
          remote: testremote2

      self:
        path: the-manifest-path
    '''
    r1 = Remote('testremote1', 'https://example1.com')
    r2 = Remote('testremote2', 'https://example2.com')

    manifest = Manifest.from_data(yaml.safe_load(content))

    expected = [
        ManifestProject(path='the-manifest-path'),
        Project('testproject1',
                None,
                path='testproject1',
                clone_depth=None,
                revision='rev1',
                remote=r1),
        Project('testproject2',
                None,
                path='testproject2',
                clone_depth=None,
                revision='master',
                remote=r2)
    ]

    # Check the remotes are as expected.
    assert list(manifest.remotes) == [r1, r2]

    # Check the projects are as expected.
    for p, e in zip(manifest.projects, expected):
        check_proj_consistency(p, e)
Exemplo n.º 15
0
def test_defaults_and_url(west_topdir):
    # an explicit URL overrides the defaults attribute.

    content = '''\
    manifest:
      defaults:
        remote: remote1
      remotes:
        - name: remote1
          url-base: https://url1.com/
      projects:
        - name: testproject
          url: https://url2.com/testproject
    '''
    manifest = Manifest.from_data(yaml.safe_load(content))
    assert manifest.projects[1].url == 'https://url2.com/testproject'
Exemplo n.º 16
0
def test_west_is_ok():
    # Projects named west are allowed now.
    content = '''\
    manifest:
      remotes:
        - name: testremote
          url-base: https://example.com

      projects:
        - name: west
          remote: testremote
    '''
    with patch('west.util.west_topdir',
               return_value=os.path.realpath('/west_top')):
        manifest = Manifest.from_data(yaml.safe_load(content))
    assert manifest.projects[1].name == 'west'
Exemplo n.º 17
0
def test_path():
    # Projects must be able to override their default paths.
    content = '''\
    manifest:
      remotes:
        - name: testremote
          url: https://example.com
      projects:
        - name: testproject
          remote: testremote
          path: sub/directory
    '''
    with patch('west.util.west_topdir', return_value='/west_top'):
        manifest = Manifest.from_data(yaml.safe_load(content))
    assert manifest.projects[0].path == 'sub/directory'
    assert manifest.projects[0].abspath == '/west_top/sub/directory'
Exemplo n.º 18
0
def test_no_defaults(config_file_project_setup):
    # Manifests with no defaults should work.
    content = '''\
    manifest:
      remotes:
        - name: testremote1
          url-base: https://example1.com
        - name: testremote2
          url-base: https://example2.com

      projects:
        - name: testproject1
          remote: testremote1
          revision: rev1
        - name: testproject2
          remote: testremote2
    '''
    r1 = Remote('testremote1', 'https://example1.com')
    r2 = Remote('testremote2', 'https://example2.com')

    with patch('west.util.west_topdir', return_value='/west_top'):
        manifest = Manifest.from_data(yaml.safe_load(content))

        expected = [
            SpecialProject('manifestproject', path='manifestproject'),
            Project('testproject1',
                    r1,
                    None,
                    path='testproject1',
                    clone_depth=None,
                    revision='rev1'),
            Project('testproject2',
                    r2,
                    None,
                    path='testproject2',
                    clone_depth=None,
                    revision='master')
        ]

    # Check the remotes are as expected.
    assert list(manifest.remotes) == [r1, r2]

    # Check the projects are as expected.
    for p, e in zip(manifest.projects, expected):
        deep_eq_check(p, e)
    assert all(p.abspath == os.path.realpath(os.path.join('/west_top', p.path))
               for p in manifest.projects)
Exemplo n.º 19
0
def test_path():
    # Projects must be able to override their default paths.
    # Absolute paths should reflect this setting.

    content = '''\
    manifest:
      remotes:
        - name: testremote
          url-base: https://example.com
      projects:
        - name: testproject
          remote: testremote
          path: sub/directory
    '''
    manifest = Manifest.from_data(yaml.safe_load(content), topdir='/west_top')
    assert manifest.projects[1].path == 'sub' + os.path.sep + 'directory'
    assert manifest.projects[1].posixpath == '/west_top/sub/directory'
Exemplo n.º 20
0
    def zephyr_manifest(self):
        # load the upstream manifest. the west.manifest APIs guarantee
        # in this case that its project hierarchy is rooted in the NCS
        # directory.

        z_project = self.manifest.get_projects(['zephyr'],
                                               allow_paths=False,
                                               only_cloned=True)[0]
        cp = z_project.git(f'show {self.zephyr_rev}:west.yml',
                           capture_stdout=True, check=True)
        z_west_yml = cp.stdout.decode('utf-8')
        try:
            return Manifest.from_data(source_data=yaml.safe_load(z_west_yml),
                                      topdir=self.topdir)
        except MalformedManifest:
            log.die(f"can't load zephyr manifest; file {z_west_yml} "
                    "is malformed")
Exemplo n.º 21
0
def test_west_commands():
    # Projects may specify subdirectories containing west commands.
    content = '''\
    manifest:
      remotes:
        - name: testremote
          url-base: https://example.com

      projects:
        - name: zephyr
          remote: testremote
          west-commands: some-path/west-commands.yml
    '''
    with patch('west.util.west_topdir',
               return_value=os.path.realpath('/west_top')):
        manifest = Manifest.from_data(yaml.safe_load(content))
    assert len(manifest.projects) == 2
    assert manifest.projects[-1].west_commands == 'some-path/west-commands.yml'
Exemplo n.º 22
0
def test_multiple_remotes():
    # More than one remote may be used, and one of them may be used as
    # the default.

    content = '''\
    manifest:
      defaults:
        remote: testremote2

      remotes:
        - name: testremote1
          url-base: https://example1.com
        - name: testremote2
          url-base: https://example2.com

      projects:
        - name: testproject1
          remote: testremote1
          revision: rev1
        - name: testproject2
          remote: testremote2
        - name: testproject3
    '''
    r1 = Remote('testremote1', 'https://example1.com')
    r2 = Remote('testremote2', 'https://example2.com')

    manifest = Manifest.from_data(yaml.safe_load(content))

    expected = [
        Project('testproject1', revision='rev1', remote=r1),
        Project('testproject2', remote=r2),
        Project('testproject3', remote=r2)
    ]

    # Check the remotes are as expected.
    assert list(manifest.remotes) == [r1, r2]

    # Check the projects are as expected.
    for p, e in zip(manifest.projects[1:], expected):
        check_proj_consistency(p, e)

    # Throw in an extra check that absolute paths are not available,
    # just for fun.
    assert all(p.abspath is None for p in manifest.projects)
Exemplo n.º 23
0
    def zephyr_manifest(self):
        # Load the upstream manifest. Since west v0.13, the resulting
        # projects have no absolute paths, so we'll fix those up so
        # they're relative to our own topdir. (We can't use
        # Manifest.from_file() in this case because self.zephyr_rev is
        # not what's checked out on the file system).

        z_project = self.manifest.get_projects(['zephyr'],
                                               allow_paths=False,
                                               only_cloned=True)[0]
        cp = z_project.git(f'show {self.zephyr_rev}:west.yml',
                           capture_stdout=True,
                           check=True)
        z_west_yml = cp.stdout.decode('utf-8')
        try:
            ret = Manifest.from_data(source_data=yaml.safe_load(z_west_yml),
                                     import_flags=ImportFlag.IGNORE)
            if WEST_V0_13_0_OR_LATER:
                for project in ret.projects:
                    project.topdir = self.manifest.topdir
            return ret
        except MalformedManifest:
            log.die(f"can't load zephyr manifest; file {z_west_yml} "
                    "is malformed")
Exemplo n.º 24
0
def test_manifest_attrs():
    # test that the manifest repository, when represented as a project,
    # has attributes which make sense.

    # Case 1: everything at defaults
    content = '''\
    manifest:
      projects:
        - name: name
          url: url
    '''
    manifest = Manifest.from_data(yaml.safe_load(content))
    mp = manifest.projects[0]
    assert mp.name == 'manifest'
    assert mp.path is None
    assert mp.topdir is None
    assert mp.abspath is None
    assert mp.posixpath is None
    assert mp.url is None
    assert mp.remote is None
    assert mp.revision == 'HEAD'
    assert mp.clone_depth is None

    # Case 2: path etc. are specified, but not topdir
    content = '''\
    manifest:
      projects:
        - name: name
          url: url
      self:
        path: my-path
        west-commands: cmds.yml
    '''
    manifest = Manifest.from_data(yaml.safe_load(content))
    mp = manifest.projects[0]
    assert mp.name == 'manifest'
    assert mp.path == 'my-path'
    assert mp.west_commands == 'cmds.yml'
    assert mp.topdir is None
    assert mp.abspath is None
    assert mp.posixpath is None
    assert mp.url is None
    assert mp.remote is None
    assert mp.revision == 'HEAD'
    assert mp.clone_depth is None

    # Case 3: path etc. and topdir are all specified
    content = '''\
    manifest:
      projects:
        - name: name
          url: url
      self:
        path: my-path
        west-commands: cmds.yml
    '''
    manifest = Manifest.from_data(yaml.safe_load(content),
                                  manifest_path='should-be-ignored',
                                  topdir='/west_top')
    mp = manifest.projects[0]
    assert mp.name == 'manifest'
    assert mp.path == 'my-path'
    assert mp.topdir is not None
    assert PurePath(mp.abspath) == PurePath('/west_top/my-path')
    assert mp.posixpath is not None
    assert mp.west_commands == 'cmds.yml'
    assert mp.url is None
    assert mp.remote is None
    assert mp.revision == 'HEAD'
    assert mp.clone_depth is None
Exemplo n.º 25
0
def test_invalid(invalid):
    with open(invalid, 'r') as f:
        data = yaml.safe_load(f.read())

    with pytest.raises(MalformedManifest):
        Manifest.from_data(source_data=data)
Exemplo n.º 26
0
def test_data_and_topdir(tmpdir):
    # If you specify the topdir along with some source data, you will
    # get absolute paths, even if it doesn't exist.

    topdir = str(tmpdir)

    # Case 1: manifest has no path (projects always have paths)
    content = '''\
    manifest:
        projects:
          - name: my-cool-project
            url: from-manifest-dir
    '''
    manifest = Manifest.from_data(source_data=yaml.safe_load(content),
                                  topdir=topdir)
    assert manifest.topdir == topdir
    mproj = manifest.projects[0]
    assert mproj.topdir == topdir
    assert mproj.path is None
    p1 = manifest.projects[1]
    assert PurePath(p1.topdir) == PurePath(topdir)
    assert PurePath(p1.abspath) == PurePath(str(tmpdir / 'my-cool-project'))

    # Case 2: manifest path is provided programmatically
    content = '''\
    manifest:
        projects:
          - name: my-cool-project
            url: from-manifest-dir
    '''
    manifest = Manifest.from_data(source_data=yaml.safe_load(content),
                                  manifest_path='from-api',
                                  topdir=topdir)
    assert manifest.topdir == topdir
    mproj = manifest.projects[0]
    assert PurePath(mproj.topdir).is_absolute()
    assert PurePath(mproj.topdir) == PurePath(topdir)
    assert mproj.path == 'from-api'
    assert PurePath(mproj.abspath).is_absolute()
    assert PurePath(mproj.abspath) == PurePath(str(tmpdir / 'from-api'))
    p1 = manifest.projects[1]
    assert PurePath(p1.topdir) == PurePath(topdir)
    assert PurePath(p1.abspath) == PurePath(str(tmpdir / 'my-cool-project'))

    # Case 3: manifest has a self path. This must override the
    # manifest_path kwarg.
    content = '''\
    manifest:
        projects:
          - name: my-cool-project
            url: from-manifest-dir
        self:
            path: from-content
    '''
    manifest = Manifest.from_data(source_data=yaml.safe_load(content),
                                  manifest_path='should-be-ignored',
                                  topdir=topdir)
    assert manifest.topdir == topdir
    mproj = manifest.projects[0]
    assert mproj.path == 'from-content'
    assert PurePath(mproj.abspath) == PurePath(str(tmpdir / 'from-content'))
    p1 = manifest.projects[1]
    assert p1.path == 'my-cool-project'
    assert PurePath(p1.abspath) == PurePath(str(tmpdir / 'my-cool-project'))

    # Case 4: project has a path.
    content = '''\
    manifest:
        projects:
          - name: my-cool-project
            url: from-manifest-dir
            path: project-path
        self:
            path: manifest-path
    '''
    manifest = Manifest.from_data(source_data=yaml.safe_load(content),
                                  manifest_path='should-be-ignored',
                                  topdir=topdir)
    assert manifest.topdir == topdir
    mproj = manifest.projects[0]
    assert mproj.path == 'manifest-path'
    assert PurePath(mproj.abspath) == PurePath(str(tmpdir / 'manifest-path'))
    p1 = manifest.projects[1]
    assert p1.path == 'project-path'
    assert PurePath(p1.abspath) == PurePath(str(tmpdir / 'project-path'))
Exemplo n.º 27
0
def test_repo_path(west_topdir):
    # a project's fetch URL may be specified by combining a remote and
    # repo-path. this overrides the default use of the project's name
    # as the repo-path.

    # default remote + repo-path
    content = '''\
    manifest:
      defaults:
        remote: remote1
      remotes:
        - name: remote1
          url-base: https://example.com
      projects:
        - name: testproject
          repo-path: some/path
    '''
    manifest = Manifest.from_data(yaml.safe_load(content))
    assert manifest.projects[1].url == 'https://example.com/some/path'

    # non-default remote + repo-path
    content = '''\
    manifest:
      defaults:
        remote: remote1
      remotes:
        - name: remote1
          url-base: https://url1.com
        - name: remote2
          url-base: https://url2.com
      projects:
        - name: testproject
          remote: remote2
          repo-path: path
    '''
    manifest = Manifest.from_data(yaml.safe_load(content))
    assert manifest.projects[1].url == 'https://url2.com/path'

    # same project checked out under two different names
    content = '''\
    manifest:
      defaults:
        remote: remote1
      remotes:
        - name: remote1
          url-base: https://url1.com
      projects:
        - name: testproject_v1
          revision: v1.0
          repo-path: testproject
        - name: testproject_v2
          revision: v2.0
          repo-path: testproject
    '''
    manifest = Manifest.from_data(yaml.safe_load(content))
    p1, p2 = manifest.projects[1:]
    r = Remote('remote1', 'https://url1.com')
    assert p1.url == 'https://url1.com/testproject'
    assert p1.url == p2.url
    expected1 = Project('testproject_v1',
                        defaults=None,
                        path='testproject_v1',
                        clone_depth=None,
                        revision='v1.0',
                        west_commands=None,
                        remote=r,
                        repo_path='testproject',
                        url=None)
    expected2 = Project('testproject_v2',
                        defaults=None,
                        path='testproject_v2',
                        clone_depth=None,
                        revision='v2.0',
                        west_commands=None,
                        remote=r,
                        repo_path='testproject',
                        url=None)
    deep_eq_check(p1, expected1)
    deep_eq_check(p2, expected2)