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

GothenburgBitFactory / taskwarrior / 12357332129

16 Dec 2024 04:49PM UTC coverage: 84.906% (-0.6%) from 85.522%
12357332129

Pull #3725

github

web-flow
[pre-commit.ci] pre-commit autoupdate

updates:
- [github.com/pre-commit/mirrors-clang-format: v19.1.4 → v19.1.5](https://github.com/pre-commit/mirrors-clang-format/compare/v19.1.4...v19.1.5)
Pull Request #3725: [pre-commit.ci] pre-commit autoupdate

19278 of 22705 relevant lines covered (84.91%)

23266.13 hits per line

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

88.43
/src/commands/CmdDiagnostics.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 <CmdDiagnostics.h>
31
#include <Context.h>
32
#include <RX.h>
33
#include <format.h>
34
#include <shared.h>
35
#include <stdlib.h>
36
#include <time.h>
37

38
#include <algorithm>
39
#include <iomanip>
40
#include <sstream>
41
#ifdef HAVE_COMMIT
42
#include <commit.h>
43
#endif
44

45
////////////////////////////////////////////////////////////////////////////////
46
CmdDiagnostics::CmdDiagnostics() {
4,495✔
47
  _keyword = "diagnostics";
4,495✔
48
  _usage = "task          diagnostics";
4,495✔
49
  _description = "Platform, build and environment details";
4,495✔
50
  _read_only = true;
4,495✔
51
  _displays_id = false;
4,495✔
52
  _needs_gc = false;
4,495✔
53
  _uses_context = false;
4,495✔
54
  _accepts_filter = false;
4,495✔
55
  _accepts_modifications = false;
4,495✔
56
  _accepts_miscellaneous = false;
4,495✔
57
  _category = Command::Category::misc;
4,495✔
58
}
4,495✔
59

60
////////////////////////////////////////////////////////////////////////////////
61
// This command will generate output that is intended to help diagnose problems.
62
//
63
// Although this will change over time, initially this command will answer the
64
// kind of questions we always have to ask whenever something is wrong.
65
int CmdDiagnostics::execute(std::string& output) {
7✔
66
  Color bold;
7✔
67
  if (Context::getContext().color()) bold = Color("bold");
9✔
68

69
  std::stringstream out;
7✔
70
  out << '\n' << bold.colorize(PACKAGE_STRING) << '\n';
14✔
71

72
  out << "   Platform: " << osName() << "\n\n";
7✔
73

74
  // Compiler.
75
  out << bold.colorize("Compiler") << '\n'
14✔
76
#ifdef __VERSION__
77
      << "    Version: " << __VERSION__ << '\n'
78
#endif
79
      << "       Caps:"
80
#ifdef __STDC__
81
      << " +stdc"
82
#endif
83
#ifdef __STDC_HOSTED__
84
      << " +stdc_hosted"
85
#endif
86
#ifdef __STDC_VERSION__
87
      << " +" << __STDC_VERSION__
88
#endif
89
#ifdef _POSIX_VERSION
90
      << " +" << _POSIX_VERSION
91
#endif
92
#ifdef _POSIX2_C_VERSION
93
      << " +" << _POSIX2_C_VERSION
94
#endif
95
#ifdef _ILP32
96
      << " +ILP32"
97
#endif
98
#ifdef _LP64
99
      << " +LP64"
100
#endif
101
      << " +c" << 8 * sizeof(char) << " +i" << 8 * sizeof(int) << " +l" << 8 * sizeof(long)
7✔
102
      << " +vp" << 8 * sizeof(void*) << " +time_t" << 8 * sizeof(time_t) << '\n';
7✔
103

104
  // Compiler compliance level.
105
  out << " Compliance: " << cppCompliance() << "\n\n";
7✔
106

107
  out << bold.colorize("Build Features") << '\n'
14✔
108

109
#ifdef HAVE_COMMIT
110
      << "     Commit: " << COMMIT << '\n'
111
#endif
112
      << "      CMake: " << CMAKE_VERSION << '\n';
7✔
113

114
  out << "    libuuid: "
115
#ifdef HAVE_UUID_UNPARSE_LOWER
116
      << "libuuid + uuid_unparse_lower"
117
#else
118
      << "libuuid, no uuid_unparse_lower"
119
#endif
120
      << '\n';
7✔
121

122
  out << " Build type: "
123
#ifdef CMAKE_BUILD_TYPE
124
      << CMAKE_BUILD_TYPE
125
#else
126
      << '-'
127
#endif
128
      << "\n\n";
7✔
129

130
  // Config: .taskrc found, readable, writable
131
  File rcFile(Context::getContext().config.file());
7✔
132
  out << bold.colorize("Configuration") << '\n'
14✔
133
      << "       File: " << rcFile._data << ' ' << (rcFile.exists() ? "(found)" : "(missing)")
14✔
134
      << ", " << rcFile.size() << ' ' << "bytes"
7✔
135
      << ", mode " << std::setbase(8) << rcFile.mode() << '\n';
7✔
136

137
  // Config: data.location found, readable, writable
138
  File location(Context::getContext().config.get("data.location"));
14✔
139
  out << "       Data: " << location._data << ' ' << (location.exists() ? "(found)" : "(missing)")
14✔
140
      << ", " << (location.is_directory() ? "dir" : "?") << ", mode " << std::setbase(8)
7✔
141
      << location.mode() << '\n';
7✔
142

143
  char* env = getenv("TASKRC");
7✔
144
  if (env) out << "     TASKRC: " << env << '\n';
7✔
145

146
  env = getenv("TASKDATA");
7✔
147
  if (env) out << "   TASKDATA: " << env << '\n';
7✔
148

149
  out << "         GC: " << (Context::getContext().config.getBoolean("gc") ? "Enabled" : "Disabled")
21✔
150
      << '\n';
14✔
151

152
  // Determine rc.editor/$EDITOR/$VISUAL.
153
  char* peditor;
154
  if (Context::getContext().config.get("editor") != "")
21✔
155
    out << "  rc.editor: " << Context::getContext().config.get("editor") << '\n';
3✔
156
  else if ((peditor = getenv("VISUAL")) != nullptr)
6✔
157
    out << "    $VISUAL: " << peditor << '\n';
×
158
  else if ((peditor = getenv("EDITOR")) != nullptr)
6✔
159
    out << "    $EDITOR: " << peditor << '\n';
×
160

161
  // Display hook status.
162
  Path hookLocation;
7✔
163
  if (Context::getContext().config.has("hooks.location")) {
21✔
164
    hookLocation = Path(Context::getContext().config.get("hooks.location"));
×
165
  } else {
166
    hookLocation = Path(Context::getContext().config.get("data.location"));
21✔
167
    hookLocation += "hooks";
14✔
168
  }
169

170
  out << bold.colorize("Hooks") << '\n'
14✔
171
      << "     System: "
172
      << (Context::getContext().config.getBoolean("hooks") ? "Enabled" : "Disabled") << '\n'
21✔
173
      << "   Location: " << static_cast<std::string>(hookLocation) << '\n';
14✔
174

175
  auto hooks = Context::getContext().hooks.list();
7✔
176
  if (hooks.size()) {
7✔
177
    unsigned int longest = 0;
1✔
178
    for (auto& hook : hooks)
5✔
179
      if (hook.length() > longest) longest = hook.length();
4✔
180
    longest -= hookLocation._data.length() + 1;
1✔
181

182
    out << "     Active: ";
1✔
183
    int count = 0;
1✔
184
    for (auto& hook : hooks) {
5✔
185
      Path p(hook);
4✔
186
      if (!p.is_directory()) {
4✔
187
        auto name = p.name();
4✔
188

189
        if (p.executable() &&
6✔
190
            (name.substr(0, 6) == "on-add" || name.substr(0, 9) == "on-modify" ||
6✔
191
             name.substr(0, 9) == "on-launch" || name.substr(0, 7) == "on-exit")) {
6✔
192
          out << (count++ ? "             " : "");
1✔
193

194
          out.width(longest);
1✔
195
          out << std::left << name << " (executable)" << (p.is_link() ? " (symlink)" : "") << '\n';
1✔
196
        }
197
      }
4✔
198
    }
4✔
199

200
    if (!count) out << '\n';
1✔
201

202
    out << "   Inactive: ";
1✔
203
    count = 0;
1✔
204
    for (auto& hook : hooks) {
5✔
205
      Path p(hook);
4✔
206
      if (!p.is_directory()) {
4✔
207
        auto name = p.name();
4✔
208

209
        if (!p.executable() ||
6✔
210
            (name.substr(0, 6) != "on-add" && name.substr(0, 9) != "on-modify" &&
6✔
211
             name.substr(0, 9) != "on-launch" && name.substr(0, 7) != "on-exit")) {
6✔
212
          out << (count++ ? "             " : "");
3✔
213

214
          out.width(longest);
3✔
215
          out << std::left << name << (p.executable() ? " (executable)" : " (not executable)")
3✔
216
              << (p.is_link() ? " (symlink)" : "")
6✔
217
              << ((name.substr(0, 6) == "on-add" || name.substr(0, 9) == "on-modify" ||
6✔
218
                   name.substr(0, 9) == "on-launch" || name.substr(0, 7) == "on-exit")
6✔
219
                      ? ""
220
                      : "unrecognized hook name")
221
              << '\n';
6✔
222
        }
223
      }
4✔
224
    }
4✔
225

226
    if (!count) out << '\n';
1✔
227
  } else
228
    out << "             (-none-)\n";
6✔
229

230
  out << '\n';
7✔
231

232
  // Verify UUIDs are all unique.
233
  out << bold.colorize("Tests") << '\n';
7✔
234

235
  // Report terminal dimensions.
236
  out << "   Terminal: " << Context::getContext().getWidth() << 'x'
7✔
237
      << Context::getContext().getHeight() << '\n';
7✔
238

239
  // Check all the UUID references
240
  auto all = Context::getContext().tdb2.all_tasks();
7✔
241

242
  bool noBrokenRefs = true;
7✔
243
  out << " Broken ref: " << format("Scanned {1} tasks for broken references:", all.size()) << '\n';
14✔
244

245
  for (auto& task : all) {
7✔
246
    // Check dependencies
247
    for (auto& uuid : task.getDependencyUUIDs()) {
×
248
      if (!Context::getContext().tdb2.has(uuid)) {
×
249
        out << "             "
250
            << format("Task {1} depends on nonexistent task: {2}", task.get("uuid"), uuid) << '\n';
×
251
        noBrokenRefs = false;
×
252
      }
253
    }
×
254

255
    // Check recurrence parent
256
    auto parentUUID = task.get("parent");
×
257

258
    if (parentUUID != "" && !Context::getContext().tdb2.has(parentUUID)) {
×
259
      out << "             "
260
          << format("Task {1} has nonexistent recurrence template {2}", task.get("uuid"),
×
261
                    parentUUID)
262
          << '\n';
×
263
      noBrokenRefs = false;
×
264
    }
265
  }
×
266

267
  if (noBrokenRefs) out << "             No broken references found\n";
7✔
268

269
  out << '\n';
7✔
270
  output = out.str();
7✔
271
  return 0;
7✔
272
}
7✔
273

274
////////////////////////////////////////////////////////////////////////////////
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

© 2026 Coveralls, Inc