def test_import_project_release_dir(tmpdir): # Tests for a workspace that imports a directory from a project # at a fixed release. remotes = tmpdir / 'remotes' empty_project = remotes / 'empty_project' create_repo(empty_project) add_commit(empty_project, 'empty-project empty commit') imported = remotes / 'imported' create_repo(imported) add_commit(imported, 'add directory of imports', files={'test.d/1.yml': f'''\ manifest: projects: - name: west.d/1.yml-p1 url: {empty_project} - name: west.d/1.yml-p2 url: {empty_project} ''', 'test.d/2.yml': f'''\ manifest: projects: - name: west.d/2.yml-p1 url: {empty_project} '''}) add_tag(imported, 'import-tag') ws = tmpdir / 'ws' create_workspace(ws, and_git=True) manifest_repo = ws / 'mp' add_commit(manifest_repo, 'manifest repo commit', files={'west.yml': f''' manifest: projects: - name: imported url: {imported} revision: import-tag import: test.d '''}) cmd(f'init -l {manifest_repo}') with pytest.raises(ManifestImportFailed): Manifest.from_file(topdir=ws) cmd('update', cwd=ws) actual = Manifest.from_file(topdir=ws).projects expected = [ManifestProject(path='mp', topdir=ws), Project('imported', imported, revision='import-tag', topdir=ws), Project('west.d/1.yml-p1', empty_project, topdir=ws), Project('west.d/1.yml-p2', empty_project, topdir=ws), Project('west.d/2.yml-p1', empty_project, topdir=ws)] for a, e in zip(actual, expected): check_proj_consistency(a, e)
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)
def test_import_project_rolling(repos_tmpdir): # Like test_import_project_release, but with a rolling downstream # that pulls master. We also use west init -l. remotes = repos_tmpdir / 'repos' zephyr = remotes / 'zephyr' ws = repos_tmpdir / 'ws' create_workspace(ws, and_git=True) manifest_repo = ws / 'mp' create_repo(manifest_repo) add_commit(manifest_repo, 'manifest repo commit', # zephyr revision is implicitly master: files={'west.yml': f''' manifest: projects: - name: zephyr url: {zephyr} import: true '''}) cmd(f'init -l {manifest_repo}') with pytest.raises(ManifestImportFailed): Manifest.from_file(topdir=ws) cmd('update', cwd=ws) actual = Manifest.from_file(topdir=ws).projects expected = [ManifestProject(path='mp', topdir=ws), Project('zephyr', zephyr, revision='master', topdir=ws), Project('Kconfiglib', remotes / 'Kconfiglib', revision='zephyr', path='subdir/Kconfiglib', topdir=ws), Project('tagged_repo', remotes / 'tagged_repo', revision='v1.0', topdir=ws), Project('net-tools', remotes / 'net-tools', clone_depth=1, topdir=ws, west_commands='scripts/west-commands.yml')] for a, e in zip(actual, expected): check_proj_consistency(a, e) # Add a commit in the remote zephyr repository and make sure it # *does* affect our local workspace, since we're rolling with its # master branch. zephyr_ws = ws / 'zephyr' head_before = rev_parse(zephyr_ws, 'HEAD') add_commit(zephyr, 'this better show up', files={'should-clone': ''}) cmd('update', cwd=ws) assert head_before != rev_parse(zephyr_ws, 'HEAD') assert (zephyr_ws / 'should-clone').check(file=1)
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)
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)
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)
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)
def test_remote_url_init(west_topdir): # Projects must be initialized with a remote or a URL, but not both. # The resulting URLs must behave as documented. r1 = Remote('testremote1', 'https://example.com') p1 = Project('project1', None, remote=r1) assert p1.remote is r1 assert p1.url == 'https://example.com/project1' p2 = Project('project2', None, url='https://example.com/project2') assert p2.remote is None assert p2.url == 'https://example.com/project2' with pytest.raises(ValueError): Project('project3', None, remote=r1, url='not-empty') with pytest.raises(ValueError): Project('project4', None, remote=None, url=None)
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)
def _special_project(name): # Returns a Project instance for one of the special repositories in west/, # so that we can reuse the project-related functions for them remote = Remote(name=config.get(name, 'remote', fallback='origin'), url='dummy URL for {} repository'.format(name)) # 'revision' always exists and defaults to 'master' return Project(name, remote, None, revision=config.get(name, 'revision', fallback='master'), path=os.path.join('west', name))
def _special_project(name): # Returns a Project instance for one of the special repositories in west/, # so that we can reuse the project-related functions for them # TODO: Maybe the Remote class could be replaced by a single # project.remote_name field, now that we no longer use the Git remote # mechanism and fetch directly from URLs remote = Remote(name='dummy name for {} repository'.format(name), url='dummy URL for {} repository'.format(name)) # 'revision' always exists and defaults to 'master' project = Project(name, remote, None, revision=config.get(name, 'revision', fallback='master'), path=os.path.join('west', name)) # This could also be the name of a Git remote. The naming breaks a bit # here. project.url = config.get(name, 'remote', fallback='origin') return project
def test_init_with_url(west_topdir): # Test the project constructor works as expected with a URL. p = Project('p', url='some-url') assert p.name == 'p' assert p.remote is None assert p.url == 'some-url' assert p.path == 'p' assert p.abspath == os.path.realpath(os.path.join('/west_top', 'p')) posixpath = p.posixpath if platform.system() == 'Windows': posixpath = os.path.splitdrive(posixpath)[1] assert posixpath == '/west_top/p' assert p.clone_depth is None assert p.revision == 'master' assert p.west_commands is None
def test_init_with_url_and_topdir(): # Test the project constructor works as expected with a URL # and explicit top level directory. p = Project('p', url='some-url', topdir='/west_top') assert p.name == 'p' assert p.remote is None assert p.url == 'some-url' assert p.path == 'p' assert p.topdir == '/west_top' if platform.system() == 'Windows': posixpath = os.path.splitdrive(p.posixpath)[1] assert posixpath == '/west_top/p' assert p.clone_depth is None assert p.revision == 'master' assert p.west_commands is None
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)
def test_import_project_release_fork(repos_tmpdir): # Like test_import_project_release(), but with a project fork, # and using west init -l. remotes = repos_tmpdir / 'repos' zephyr = remotes / 'zephyr' add_tag(zephyr, 'zephyr-tag') fork = remotes / 'my-kconfiglib-fork' create_repo(fork) add_commit(fork, 'fork kconfiglib') add_tag(fork, 'fork-tag') ws = repos_tmpdir / 'ws' create_workspace(ws, and_git=True) manifest_repo = ws / 'mp' create_repo(manifest_repo) add_commit(manifest_repo, 'manifest repo commit', files={ 'west.yml': f''' manifest: projects: - name: zephyr url: {zephyr} revision: zephyr-tag import: true - name: Kconfiglib url: {fork} revision: fork-tag ''' }) cmd(f'init -l {manifest_repo}') with pytest.raises(ManifestImportFailed): Manifest.from_file(topdir=ws) cmd('update', cwd=ws) actual = Manifest.from_file(topdir=ws).projects expected = [ ManifestProject(path='mp', topdir=ws), Project('zephyr', zephyr, revision='zephyr-tag', topdir=ws), Project('Kconfiglib', fork, revision='fork-tag', path='Kconfiglib', topdir=ws), Project('tagged_repo', remotes / 'tagged_repo', revision='v1.0', topdir=ws), Project('net-tools', remotes / 'net-tools', clone_depth=1, topdir=ws, west_commands='scripts/west-commands.yml') ] for a, e in zip(actual, expected): check_proj_consistency(a, e) zephyr_ws = ws / 'zephyr' head_before = rev_parse(zephyr_ws, 'HEAD') add_commit(zephyr, 'this better not show up', files={'should-not-clone': ''}) cmd('update', cwd=ws) assert head_before == rev_parse(zephyr_ws, 'HEAD') actual = Manifest.from_file(topdir=ws).projects for a, e in zip(actual, expected): check_proj_consistency(a, e) assert (zephyr_ws / 'should-not-clone').check(file=0)
def test_import_project_release(repos_tmpdir): # Tests for a workspace that's based off of importing from a # project at a fixed release, with no downstream project forks. remotes = repos_tmpdir / 'repos' zephyr = remotes / 'zephyr' add_tag(zephyr, 'test-tag') # For this test, we create a remote manifest repository. This # makes sure we can clone a manifest repository which contains # imports without issue (and we don't need to clone the imported # projects.) # # On subsequent tests, we won't bother with this step. We will # just put the manifest repository directly into the workspace and # use west init -l. This also provides coverage for the -l option # in the presence of imports. manifest_remote = remotes / 'mp' create_repo(manifest_remote) add_commit(manifest_remote, 'manifest repo commit', files={ 'west.yml': f''' manifest: projects: - name: zephyr url: {zephyr} revision: test-tag import: true ''' }) # Create the workspace and verify we can't load the manifest yet # (because some imported data is missing). ws = repos_tmpdir / 'ws' cmd(f'init -m {manifest_remote} {ws}') with pytest.raises(ManifestImportFailed): # We can't load this yet, because we haven't cloned zephyr. Manifest.from_file(topdir=ws) # Run west update and make sure we can load the manifest now. cmd('update', cwd=ws) actual = Manifest.from_file(topdir=ws).projects expected = [ ManifestProject(path='mp', topdir=ws), Project('zephyr', zephyr, revision='test-tag', topdir=ws), Project('Kconfiglib', remotes / 'Kconfiglib', revision='zephyr', path='subdir/Kconfiglib', topdir=ws), Project('tagged_repo', remotes / 'tagged_repo', revision='v1.0', topdir=ws), Project('net-tools', remotes / 'net-tools', clone_depth=1, topdir=ws, west_commands='scripts/west-commands.yml') ] for a, e in zip(actual, expected): check_proj_consistency(a, e) # Add a commit in the remote zephyr repository and make sure it # doesn't affect our local workspace, since we've locked it to a # tag. zephyr_ws = ws / 'zephyr' head_before = rev_parse(zephyr_ws, 'HEAD') add_commit(zephyr, 'this better not show up', files={'should-not-clone': ''}) cmd('update', cwd=ws) assert head_before == rev_parse(zephyr_ws, 'HEAD') actual = Manifest.from_file(topdir=ws).projects for a, e in zip(actual, expected): check_proj_consistency(a, e) assert (zephyr_ws / 'should-not-clone').check(file=0)