doorstop.core.builder._set_tree()   A
last analyzed

Complexity

Conditions 1

Size

Total Lines 4
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
eloc 3
dl 0
loc 4
ccs 2
cts 2
cp 1
rs 10
c 0
b 0
f 0
cc 1
nop 1
crap 1
1
# SPDX-License-Identifier: LGPL-3.0-only
2
3 1
"""Functions to build a tree and access documents and items."""
4
5 1
import os
6 1
from typing import List, Optional
7 1
8 1
from doorstop import common
9 1
from doorstop.common import DoorstopError
10
from doorstop.core import vcs
11 1
from doorstop.core.document import Document
12 1
from doorstop.core.tree import Tree
13
14
log = common.logger(__name__)
15 1
_tree: Optional[Tree] = None  # implicit tree for convenience functions
16
17
18
def build(cwd=None, root=None, request_next_number=None) -> Tree:
19
    """Build a tree from the current working directory or explicit root.
20
21
    :param cwd: current working directory
22
    :param root: path to root of the working copy
23
    :param request_next_number: server method to get a document's next number
24
25
    :raises: :class:`~doorstop.common.DoorstopError` when the tree
26
        cannot be built
27
28 1
    :return: new :class:`~doorstop.core.tree.Tree`
29
30
    """
31 1
    documents: List[Document] = []
32 1
33
    # Find the root of the working copy
34
    cwd = cwd or os.getcwd()
35 1
    root = root or vcs.find_root(cwd)
36 1
37 1
    # Find all documents in the working copy
38 1
    log.info("looking for documents in {}...".format(root))
39 1
    _document_from_path(root, root, documents)
40 1
    for dirpath, dirnames, _ in os.walk(root):
41
        for dirname in dirnames:
42
            path = os.path.join(dirpath, dirname)
43 1
            _document_from_path(path, root, documents)
44 1
45 1
    # Build the tree
46 1
    if not documents:
47 1
        log.info("no documents found in: {}".format(root))
48 1
    log.info("building tree...")
49 1
    tree = Tree.from_list(documents, root=root)
50
    tree.request_next_number = request_next_number
51 1
    if len(tree):  # pylint: disable=len-as-condition
52 1
        log.info("built tree: {}".format(tree))
53
    else:
54
        log.info("tree is empty")
55 1
    return tree
56
57
58
def _document_from_path(path, root, documents):
59
    """Attempt to create and append a document from the specified path.
60
61
    :param path: path to a potential document
62
    :param root: path to root of working copy
63
    :param documents: list of :class:`~doorstop.core.document.Document`
64 1
        to append results
65 1
66 1
    """
67 1
    try:
68
        document = Document(path, root, tree=None)  # tree attached later
69 1
    except DoorstopError:
70 1
        pass  # no document in directory
71
    else:
72 1
        if document.skip:
73 1
            log.debug("skipped document: {}".format(document))
74
        else:
75
            log.info("found document: {}".format(document))
76 1
            documents.append(document)
77
78 1
79 1
def find_document(prefix):
80 1
    """Find a document without an explicitly building a tree."""
81
    tree = _get_tree()
82
    document = tree.find_document(prefix)
83 1
    return document
84
85 1
86 1
def find_item(uid):
87 1
    """Find an item without an explicitly building a tree."""
88
    tree = _get_tree()
89
    item = tree.find_item(uid)
90 1
    return item
91
92
93 1
def _get_tree(request_next_number=None):
94 1
    """Get a shared tree for convenience functions."""
95 1
    global _tree
96 1
    if _tree is None:
97
        _tree = build()
98
    _tree.request_next_number = request_next_number
99 1
    return _tree
100
101
102 1
def _set_tree(value):
103
    """Set the shared tree to a specific value (for testing)."""
104
    global _tree
105 1
    _tree = value
106
107
108 1
def _clear_tree():
109
    """Force the shared tree to be rebuilt."""
110
    global _tree
111
    _tree = None
112