• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

GothenburgBitFactory / taskwarrior / 10152339701

29 Jul 2024 09:45PM UTC coverage: 84.437% (+0.07%) from 84.372%
10152339701

push

github

web-flow
Merge pull request #3566 from felixschurk/add-clang-format

Add clang-format to enforce style guide

12359 of 13760 new or added lines in 147 files covered. (89.82%)

123 existing lines in 42 files now uncovered.

19070 of 22585 relevant lines covered (84.44%)

19724.02 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

94.44
/src/dependency.cpp
1
////////////////////////////////////////////////////////////////////////////////
2
//
3
// Copyright 2006 - 2021, Tomas Babej, Paul Beckingham, Federico Hernandez.
4
//
5
// Permission is hereby granted, free of charge, to any person obtaining a copy
6
// of this software and associated documentation files (the "Software"), to deal
7
// in the Software without restriction, including without limitation the rights
8
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
// copies of the Software, and to permit persons to whom the Software is
10
// furnished to do so, subject to the following conditions:
11
//
12
// The above copyright notice and this permission notice shall be included
13
// in all copies or substantial portions of the Software.
14
//
15
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
16
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
// SOFTWARE.
22
//
23
// https://www.opensource.org/licenses/mit-license.php
24
//
25
////////////////////////////////////////////////////////////////////////////////
26

27
#include <cmake.h>
28
// cmake.h include header must come first
29

30
#include <Context.h>
31
#include <format.h>
32
#include <main.h>
33
#include <shared.h>
34

35
#include <algorithm>
36
#include <iostream>
37
#include <sstream>
38
#include <stack>
39

40
#define STRING_DEPEND_BLOCKED "Task {1} is blocked by:"
41

42
////////////////////////////////////////////////////////////////////////////////
43
// Returns true if the supplied task adds a cycle to the dependency chain.
44
bool dependencyIsCircular(const Task& task) {
67✔
45
  // A new task has no UUID assigned yet, and therefore cannot be part of any
46
  // dependency chain.
47
  if (task.has("uuid")) {
67✔
48
    auto task_uuid = task.get("uuid");
72✔
49

50
    std::stack<Task> s;
36✔
51
    s.push(task);
36✔
52

53
    std::unordered_set<std::string> visited;
36✔
54
    visited.insert(task_uuid);
36✔
55

56
    while (!s.empty()) {
126✔
57
      Task& current = s.top();
92✔
58
      auto deps_current = current.getDependencyUUIDs();
92✔
59

60
      // This is a basic depth first search that always terminates given the
61
      // fact that we do not visit any task twice
62
      for (const auto& dep : deps_current) {
148✔
63
        if (Context::getContext().tdb2.get(dep, current)) {
58✔
64
          auto current_uuid = current.get("uuid");
116✔
65

66
          if (task_uuid == current_uuid) {
58✔
67
            // Cycle found, initial task reached for the second time!
68
            return true;
2✔
69
          }
70

71
          if (visited.find(current_uuid) == visited.end()) {
56✔
72
            // Push the task to the stack, if it has not been processed yet
73
            s.push(current);
56✔
74
            visited.insert(current_uuid);
56✔
75
          }
76
        }
58✔
77
      }
78

79
      s.pop();
90✔
80
    }
92✔
81
  }
40✔
82

83
  return false;
65✔
84
}
85

86
////////////////////////////////////////////////////////////////////////////////
87
// Determine whether a dependency chain is being broken, assuming that 'task' is
88
// either completed or deleted.
89
//
90
//   blocked task blocking action
91
//   ------- ---- -------- -----------------------------
92
//           [1]  2        Chain broken
93
//                         Nag message generated
94
//                         Repair offered:  1 dep:-2
95
//
96
//           [1]  2        Chain broken
97
//                3        Nag message generated
98
//                         Repair offered:  1 dep:-2,-3
99
//
100
//   1       [2]           -
101
//
102
//   1,3     [2]           -
103
//
104
//   1       [2]  3        Chain broken
105
//                         Nag message generated
106
//                         Repair offered:  2 dep:-3
107
//                                          1 dep:-2,3
108
//
109
//   1,4     [2]  3,5      Chain broken
110
//                         Nag message generated
111
//                         Repair offered:  2 dep:-3,-5
112
//                                          1 dep:3,5
113
//                                          4 dep:3,5
114
//
115
void dependencyChainOnComplete(Task& task) {
158✔
116
  auto blocking = task.getDependencyTasks();
158✔
117

118
  // If the task is anything but the tail end of a dependency chain.
119
  if (blocking.size()) {
158✔
120
    auto blocked = task.getBlockedTasks();
2✔
121

122
    // Nag about broken chain.
123
    if (Context::getContext().config.getBoolean("dependency.reminder")) {
2✔
124
      std::cout << format(STRING_DEPEND_BLOCKED, task.identifier()) << '\n';
2✔
125

126
      for (const auto& b : blocking)
4✔
127
        std::cout << "  " << b.id << ' ' << b.get("description") << '\n';
2✔
128
    }
129

130
    // If there are both blocking and blocked tasks, the chain is broken.
131
    if (blocked.size()) {
2✔
132
      if (Context::getContext().config.getBoolean("dependency.reminder")) {
1✔
133
        std::cout << "and is blocking:\n";
1✔
134

135
        for (const auto& b : blocked)
2✔
136
          std::cout << "  " << b.id << ' ' << b.get("description") << '\n';
1✔
137
      }
138

139
      if (!Context::getContext().config.getBoolean("dependency.confirmation") ||
3✔
140
          confirm("Would you like the dependency chain fixed?")) {
2✔
141
        // Repair the chain - everything in blocked should now depend on
142
        // everything in blocking, instead of task.id.
143
        for (auto& left : blocked) {
2✔
144
          left.removeDependency(task.id);
1✔
145

146
          for (const auto& right : blocking) left.addDependency(right.id);
2✔
147
        }
148

149
        // Now update TDB2, now that the updates have all occurred.
150
        for (auto& left : blocked) Context::getContext().tdb2.modify(left);
2✔
151

152
        for (auto& right : blocking) Context::getContext().tdb2.modify(right);
2✔
153
      }
154
    }
155
  }
2✔
156
}
158✔
157

158
////////////////////////////////////////////////////////////////////////////////
159
void dependencyChainOnStart(Task& task) {
46✔
160
  if (Context::getContext().config.getBoolean("dependency.reminder")) {
46✔
161
    auto blocking = task.getDependencyTasks();
46✔
162

163
    // If the task is anything but the tail end of a dependency chain, nag about
164
    // broken chain.
165
    if (blocking.size()) {
46✔
NEW
166
      std::cout << format(STRING_DEPEND_BLOCKED, task.identifier()) << '\n';
×
167

168
      for (const auto& b : blocking)
×
NEW
169
        std::cout << "  " << b.id << ' ' << b.get("description") << '\n';
×
170
    }
171
  }
46✔
172
}
46✔
173

174
////////////////////////////////////////////////////////////////////////////////
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc