def test_get_source_paths(self):
     try:
         root_dir = tempfile.mkdtemp()
         ws1 = os.path.join(root_dir, 'ws1')
         ws2 = os.path.join(root_dir, 'ws2')
         os.makedirs(ws1)
         os.makedirs(ws2)
         with open(os.path.join(ws1, ALPINE_MARKER_FILE), 'w') as fhand:
             fhand.write('loc1;loc2')
         with open(os.path.join(ws2, ALPINE_MARKER_FILE), 'w') as fhand:
             fhand.write('')
         self.assertEqual(['loc1', 'loc2'], get_source_paths(ws1))
         self.assertEqual([], get_source_paths(ws2))
         self.assertRaises(ValueError, get_source_paths, root_dir)
     finally:
         shutil.rmtree(root_dir)
def find_in_workspaces(search_dirs=None, project=None, path=None, _workspaces=get_workspaces(), considered_paths=None, first_matching_workspace_only=False, first_match_only=False):
    '''
    Find all paths which match the search criteria.
    All workspaces are searched in order.
    Each workspace, each search_in subfolder, the project name and the path are concatenated to define a candidate path.
    If the candidate path exists it is appended to the result list.
    Note: the search might return multiple paths for 'share' from devel- and source-space.

    :param search_dir: The list of subfolders to search in (default contains all valid values: 'bin', 'etc', 'lib', 'libexec', 'share'), ``list``
    :param project: The project name to search for (optional, not possible with the global search_in folders 'bin' and 'lib'), ``str``
    :param path: The path, ``str``
    :param _workspaces: (optional, used for unit tests), the list of workspaces to use.
    :param considered_paths: If not None, function will append all path that were searched
    :param first_matching_workspace_only: if True returns all results found for first workspace with results
    :param first_match_only: if True returns first path found (supercedes first_matching_workspace_only)
    :raises ValueError: if search_dirs contains an invalid folder name
    :returns: List of paths
    '''
    search_dirs = _get_valid_search_dirs(search_dirs, project)

    paths = []
    existing_paths = []
    try:
        for workspace in (_workspaces or []):
            for sub in search_dirs:
                # search in workspace
                p = os.path.join(workspace, sub if sub != 'libexec' else 'lib')
                if project:
                    p = os.path.join(p, project)
                if path:
                    p = os.path.join(p, path)
                paths.append(p)
                if os.path.exists(p):
                    existing_paths.append(p)
                    if first_match_only:
                        raise StopIteration

                # for search in share also consider source spaces
                if project is not None and sub == 'share':
                    source_paths = get_source_paths(workspace)
                    for source_path in source_paths:
                        packages = find_projects(source_path)
                        matching_packages = [p for p, pkg in packages.items() if pkg.name == project]
                        if matching_packages:
                            p = os.path.join(source_path, matching_packages[0])
                            if path is not None:
                                p = os.path.join(p, path)
                            paths.append(p)
                            if os.path.exists(p):
                                existing_paths.append(p)
                                if first_match_only:
                                    raise StopIteration

            if first_matching_workspace_only and existing_paths:
                break

    except StopIteration:
        pass

    if considered_paths is not None:
        considered_paths.extend(paths)

    return existing_paths
def init_workspace(workspace_dir):
    """
    Create a toplevel CMakeLists.txt in the root of a workspace.

    The toplevel.cmake file is looked up either in the alpine
    workspaces contained in the CMAKE_PREFIX_PATH or relative to this
    file.  Then it tries to create a symlink first and if that fails
    copies the file.

    It installs ``manifest.xml`` to ``share/${PROJECT_NAME}``.

    .. note:: The symlink is absolute when alpine is found outside
      the workspace_dir (since that indicates a different workspace
      and it may change relative location to the workspace referenced
      as a parameter). The symlink is relative when alpine is part of
      the to-be-initialized workspace.

    :param workspace_dir: the path to the workspace where the
      CMakeLists.txt should be created
    :type workspace_dir: string
    """
    # verify that destination file does not exist
    dst = os.path.join(workspace_dir, 'CMakeLists.txt')
    if os.path.exists(dst):
        raise RuntimeError('File "%s" already exists' % dst)

    src_file_path = None
    checked = []

    # look in to-be-initialized workspace first
    src = os.path.join(workspace_dir, 'alpine', 'cmake', 'toplevel.cmake')
    if os.path.isfile(src):
        src_file_path = os.path.relpath(src, workspace_dir)
    else:
        checked.append(src)

    # search for toplevel file in all workspaces
    if src_file_path is None:
        workspaces = get_workspaces()
        for workspace in workspaces:
            source_paths = get_source_paths(workspace)
            if len(source_paths) == 0:
                # try from install space
                src = os.path.join(workspace, 'alpine', 'cmake', 'toplevel.cmake')
                if os.path.isfile(src):
                    src_file_path = src
                    break
                else:
                    checked.append(src)
            else:
                # try from all source spaces
                for source_path in source_paths:
                    src = os.path.join(source_path, 'alpine', 'cmake', 'toplevel.cmake')
                    if os.path.isfile(src):
                        src_file_path = src
                        break
                    else:
                        checked.append(src)

    # search for toplevel file in relative locations
    if src_file_path is None:
        relative_cmake_paths = []
        # when alpine is in source space
        relative_cmake_paths.append(os.path.join('..', '..', 'cmake'))
        # when alpine is installed (with Python code in lib/pythonX.Y/[dist|site]-packages)
        relative_cmake_paths.append(os.path.join('..', '..', '..', '..', 'share', 'alpine', 'cmake'))
        # when alpine is installed (with Python code in lib/site-packages)
        relative_cmake_paths.append(os.path.join('..', '..', '..', 'share', 'alpine', 'cmake'))
        for relative_cmake_path in relative_cmake_paths:
            src = os.path.abspath(os.path.join(os.path.dirname(__file__), relative_cmake_path, 'toplevel.cmake'))
            if os.path.isfile(src):
                src_file_path = src
                break
            else:
                checked.append(src)

    if src_file_path is None:
        raise RuntimeError('Could neither find file "toplevel.cmake" in any workspace nor relative, checked the following paths:\n%s' % ('\n'.join(checked)))
    _symlink_or_copy(src_file_path, dst)