| Total Complexity | 127 |
| Total Lines | 777 |
| Duplicated Lines | 9.52 % |
| Changes | 0 | ||
Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.
Common duplication problems, and corresponding solutions are:
Complex classes like doorstop.cli.commands often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
| 1 | """Command functions.""" |
||
| 2 | |||
| 3 | import os |
||
| 4 | import time |
||
| 5 | |||
| 6 | from doorstop import common |
||
| 7 | from doorstop.cli import utilities |
||
| 8 | from doorstop.core.builder import build |
||
| 9 | from doorstop.core import editor, importer, exporter, publisher |
||
| 10 | from doorstop import server |
||
| 11 | # add import |
||
|
|
|||
| 12 | from doorstop.core.my_programs import valMatrix, verMatrix, finder |
||
| 13 | # end add imports |
||
| 14 | |||
| 15 | log = common.logger(__name__) |
||
| 16 | |||
| 17 | |||
| 18 | def get(name): |
||
| 19 | """Get a command function by name.""" |
||
| 20 | if name: |
||
| 21 | log.debug("running command '{}'...".format(name)) |
||
| 22 | return globals()['run_' + name] |
||
| 23 | else: |
||
| 24 | log.debug("launching main command...") |
||
| 25 | return run |
||
| 26 | |||
| 27 | |||
| 28 | def run(args, cwd, error, catch=True): # pylint: disable=W0613 |
||
| 29 | """Process arguments and run the `doorstop` subcommand. |
||
| 30 | |||
| 31 | :param args: Namespace of CLI arguments |
||
| 32 | :param cwd: current working directory |
||
| 33 | :param error: function to call for CLI errors |
||
| 34 | :param catch: catch and log :class:`~doorstop.common.DoorstopError` |
||
| 35 | |||
| 36 | """ |
||
| 37 | with utilities.capture(catch=catch) as success: |
||
| 38 | |||
| 39 | # get the tree |
||
| 40 | tree = _get_tree(args, cwd, load=True) |
||
| 41 | |||
| 42 | # validate it |
||
| 43 | utilities.show("validating items...", flush=True) |
||
| 44 | valid = tree.validate() |
||
| 45 | |||
| 46 | if not success: |
||
| 47 | return False |
||
| 48 | |||
| 49 | if len(tree) > 1 and valid: |
||
| 50 | utilities.show('\n' + tree.draw() + '\n') |
||
| 51 | |||
| 52 | return valid |
||
| 53 | |||
| 54 | |||
| 55 | def run_create(args, cwd, _, catch=True): |
||
| 56 | """Process arguments and run the `doorstop create` subcommand. |
||
| 57 | |||
| 58 | :param args: Namespace of CLI arguments |
||
| 59 | :param cwd: current working directory |
||
| 60 | :param error: function to call for CLI errors |
||
| 61 | :param catch: catch and log :class:`~doorstop.common.DoorstopError` |
||
| 62 | |||
| 63 | """ |
||
| 64 | with utilities.capture(catch=catch) as success: |
||
| 65 | |||
| 66 | # get the tree |
||
| 67 | tree = _get_tree(args, cwd) |
||
| 68 | |||
| 69 | # create a new document |
||
| 70 | document = tree.create_document(args.path, args.prefix, |
||
| 71 | parent=args.parent, digits=args.digits) |
||
| 72 | |||
| 73 | if not success: |
||
| 74 | return False |
||
| 75 | |||
| 76 | utilities.show("created document: {} ({})".format(document.prefix, |
||
| 77 | document.relpath)) |
||
| 78 | return True |
||
| 79 | |||
| 80 | |||
| 81 | def run_delete(args, cwd, _, catch=True): |
||
| 82 | """Process arguments and run the `doorstop delete` subcommand. |
||
| 83 | |||
| 84 | :param args: Namespace of CLI arguments |
||
| 85 | :param cwd: current working directory |
||
| 86 | :param error: function to call for CLI errors |
||
| 87 | :param catch: catch and log :class:`~doorstop.common.DoorstopError` |
||
| 88 | |||
| 89 | """ |
||
| 90 | with utilities.capture(catch=catch) as success: |
||
| 91 | |||
| 92 | # get the document |
||
| 93 | tree = _get_tree(args, cwd) |
||
| 94 | document = tree.find_document(args.prefix) |
||
| 95 | |||
| 96 | # delete it |
||
| 97 | prefix, relpath = document.prefix, document.relpath |
||
| 98 | document.delete() |
||
| 99 | |||
| 100 | if not success: |
||
| 101 | return False |
||
| 102 | |||
| 103 | utilities.show("deleted document: {} ({})".format(prefix, relpath)) |
||
| 104 | |||
| 105 | return True |
||
| 106 | |||
| 107 | |||
| 108 | def run_add(args, cwd, _, catch=True): |
||
| 109 | """Process arguments and run the `doorstop add` subcommand. |
||
| 110 | |||
| 111 | :param args: Namespace of CLI arguments |
||
| 112 | :param cwd: current working directory |
||
| 113 | :param error: function to call for CLI errors |
||
| 114 | :param catch: catch and log :class:`~doorstop.common.DoorstopError` |
||
| 115 | |||
| 116 | """ |
||
| 117 | with utilities.capture(catch=catch) as success: |
||
| 118 | |||
| 119 | # get the document |
||
| 120 | request_next_number = _request_next_number(args) |
||
| 121 | tree = _get_tree(args, cwd, request_next_number=request_next_number) |
||
| 122 | document = tree.find_document(args.prefix) |
||
| 123 | |||
| 124 | # add items to it |
||
| 125 | for _ in range(args.count): |
||
| 126 | item = document.add_item(level=args.level) |
||
| 127 | utilities.show("added item: {} ({})".format(item.uid, |
||
| 128 | item.relpath)) |
||
| 129 | |||
| 130 | if not success: |
||
| 131 | return False |
||
| 132 | |||
| 133 | return True |
||
| 134 | |||
| 135 | |||
| 136 | def run_remove(args, cwd, _, catch=True): |
||
| 137 | """Process arguments and run the `doorstop remove` subcommand. |
||
| 138 | |||
| 139 | :param args: Namespace of CLI arguments |
||
| 140 | :param cwd: current working directory |
||
| 141 | :param error: function to call for CLI errors |
||
| 142 | :param catch: catch and log :class:`~doorstop.common.DoorstopError` |
||
| 143 | |||
| 144 | """ |
||
| 145 | with utilities.capture(catch=catch) as success: |
||
| 146 | |||
| 147 | # get the item |
||
| 148 | tree = _get_tree(args, cwd) |
||
| 149 | item = tree.find_item(args.uid) |
||
| 150 | |||
| 151 | # delete it |
||
| 152 | item.delete() |
||
| 153 | |||
| 154 | if not success: |
||
| 155 | return False |
||
| 156 | |||
| 157 | utilities.show("removed item: {} ({})".format(item.uid, item.relpath)) |
||
| 158 | |||
| 159 | return True |
||
| 160 | |||
| 161 | |||
| 162 | def run_edit(args, cwd, error, catch=True): |
||
| 163 | """Process arguments and run the `doorstop edit` subcommand. |
||
| 164 | |||
| 165 | :param args: Namespace of CLI arguments |
||
| 166 | :param cwd: current working directory |
||
| 167 | :param error: function to call for CLI errors |
||
| 168 | :param catch: catch and log :class:`~doorstop.common.DoorstopError` |
||
| 169 | |||
| 170 | """ |
||
| 171 | item = document = None |
||
| 172 | ext = utilities.get_ext(args, error, '.yml', '.yml', whole_tree=False) |
||
| 173 | |||
| 174 | with utilities.capture(catch=catch) as success: |
||
| 175 | |||
| 176 | # get the item or document |
||
| 177 | request_next_number = _request_next_number(args) |
||
| 178 | tree = _get_tree(args, cwd, request_next_number=request_next_number) |
||
| 179 | if not args.document: |
||
| 180 | try: |
||
| 181 | item = tree.find_item(args.label) |
||
| 182 | except common.DoorstopError as exc: |
||
| 183 | if args.item: |
||
| 184 | raise exc from None |
||
| 185 | if not item: |
||
| 186 | document = tree.find_document(args.label) |
||
| 187 | |||
| 188 | # edit it |
||
| 189 | if item: |
||
| 190 | item.edit(tool=args.tool) |
||
| 191 | else: |
||
| 192 | _export_import(args, cwd, error, document, ext) |
||
| 193 | |||
| 194 | if not success: |
||
| 195 | return False |
||
| 196 | |||
| 197 | if item: |
||
| 198 | utilities.show("opened item: {} ({})".format(item.uid, item.relpath)) |
||
| 199 | |||
| 200 | return True |
||
| 201 | |||
| 202 | |||
| 203 | def run_reorder(args, cwd, error, catch=True, _tree=None): |
||
| 204 | """Process arguments and run the `doorstop reorder` subcommand. |
||
| 205 | |||
| 206 | :param args: Namespace of CLI arguments |
||
| 207 | :param cwd: current working directory |
||
| 208 | :param error: function to call for CLI errors |
||
| 209 | :param catch: catch and log :class:`~doorstop.common.DoorstopError` |
||
| 210 | |||
| 211 | """ |
||
| 212 | reordered = False |
||
| 213 | |||
| 214 | with utilities.capture(catch=catch) as success: |
||
| 215 | |||
| 216 | # get the document |
||
| 217 | tree = _tree or _get_tree(args, cwd) |
||
| 218 | document = tree.find_document(args.prefix) |
||
| 219 | |||
| 220 | if not success: |
||
| 221 | return False |
||
| 222 | |||
| 223 | with utilities.capture(catch=catch) as success: |
||
| 224 | |||
| 225 | # automatically order |
||
| 226 | if args.auto: |
||
| 227 | msg = "reordering document {}...".format(document) |
||
| 228 | utilities.show(msg, flush=True) |
||
| 229 | document.reorder(manual=False) |
||
| 230 | reordered = True |
||
| 231 | |||
| 232 | # or, reorder from a previously updated index |
||
| 233 | elif document.index: |
||
| 234 | relpath = os.path.relpath(document.index, cwd) |
||
| 235 | if utilities.ask("reorder from '{}'?".format(relpath)): |
||
| 236 | msg = "reordering document {}...".format(document) |
||
| 237 | utilities.show(msg, flush=True) |
||
| 238 | document.reorder(automatic=not args.manual) |
||
| 239 | reordered = True |
||
| 240 | else: |
||
| 241 | del document.index |
||
| 242 | |||
| 243 | # or, create a new index to update |
||
| 244 | else: |
||
| 245 | document.index = True # create index |
||
| 246 | relpath = os.path.relpath(document.index, cwd) |
||
| 247 | editor.edit(relpath, tool=args.tool) |
||
| 248 | get('reorder')(args, cwd, error, catch=False, _tree=tree) |
||
| 249 | |||
| 250 | if not success: |
||
| 251 | msg = "after fixing the error: doorstop reorder {}".format(document) |
||
| 252 | utilities.show(msg) |
||
| 253 | return False |
||
| 254 | |||
| 255 | if reordered: |
||
| 256 | utilities.show("reordered document: {}".format(document)) |
||
| 257 | |||
| 258 | return True |
||
| 259 | |||
| 260 | |||
| 261 | def run_link(args, cwd, _, catch=True): |
||
| 262 | """Process arguments and run the `doorstop link` subcommand. |
||
| 263 | |||
| 264 | :param args: Namespace of CLI arguments |
||
| 265 | :param cwd: current working directory |
||
| 266 | :param error: function to call for CLI errors |
||
| 267 | :param catch: catch and log :class:`~doorstop.common.DoorstopError` |
||
| 268 | |||
| 269 | """ |
||
| 270 | with utilities.capture(catch=catch) as success: |
||
| 271 | |||
| 272 | # get the tree |
||
| 273 | tree = _get_tree(args, cwd) |
||
| 274 | |||
| 275 | # link items |
||
| 276 | child, parent = tree.link_items(args.child, args.parent) |
||
| 277 | |||
| 278 | if not success: |
||
| 279 | return False |
||
| 280 | |||
| 281 | msg = "linked items: {} ({}) -> {} ({})".format(child.uid, |
||
| 282 | child.relpath, |
||
| 283 | parent.uid, |
||
| 284 | parent.relpath) |
||
| 285 | utilities.show(msg) |
||
| 286 | |||
| 287 | return True |
||
| 288 | |||
| 289 | |||
| 290 | def run_unlink(args, cwd, _, catch=True): |
||
| 291 | """Process arguments and run the `doorstop unlink` subcommand. |
||
| 292 | |||
| 293 | :param args: Namespace of CLI arguments |
||
| 294 | :param cwd: current working directory |
||
| 295 | :param error: function to call for CLI errors |
||
| 296 | :param catch: catch and log :class:`~doorstop.common.DoorstopError` |
||
| 297 | |||
| 298 | """ |
||
| 299 | with utilities.capture(catch=catch) as success: |
||
| 300 | |||
| 301 | # get the tree |
||
| 302 | tree = _get_tree(args, cwd) |
||
| 303 | |||
| 304 | # unlink items |
||
| 305 | child, parent = tree.unlink_items(args.child, args.parent) |
||
| 306 | |||
| 307 | if not success: |
||
| 308 | return False |
||
| 309 | |||
| 310 | msg = "unlinked items: {} ({}) -> {} ({})".format(child.uid, |
||
| 311 | child.relpath, |
||
| 312 | parent.uid, |
||
| 313 | parent.relpath) |
||
| 314 | utilities.show(msg) |
||
| 315 | |||
| 316 | return True |
||
| 317 | |||
| 318 | |||
| 319 | def run_clear(args, cwd, error, catch=True): |
||
| 320 | """Process arguments and run the `doorstop clear` subcommand. |
||
| 321 | |||
| 322 | :param args: Namespace of CLI arguments |
||
| 323 | :param cwd: current working directory |
||
| 324 | :param error: function to call for CLI errors |
||
| 325 | :param catch: catch and log :class:`~doorstop.common.DoorstopError` |
||
| 326 | |||
| 327 | """ |
||
| 328 | with utilities.capture(catch=catch) as success: |
||
| 329 | |||
| 330 | for item in _iter_items(args, cwd, error): |
||
| 331 | msg = "clearing item {}'s suspect links...".format(item.uid) |
||
| 332 | utilities.show(msg) |
||
| 333 | item.clear() |
||
| 334 | |||
| 335 | if not success: |
||
| 336 | return False |
||
| 337 | |||
| 338 | return True |
||
| 339 | |||
| 340 | |||
| 341 | def run_review(args, cwd, error, catch=True): |
||
| 342 | """Process arguments and run the `doorstop review` subcommand. |
||
| 343 | |||
| 344 | :param args: Namespace of CLI arguments |
||
| 345 | :param cwd: current working directory |
||
| 346 | :param error: function to call for CLI errors |
||
| 347 | :param catch: catch and log :class:`~doorstop.common.DoorstopError` |
||
| 348 | |||
| 349 | """ |
||
| 350 | with utilities.capture(catch=catch) as success: |
||
| 351 | |||
| 352 | for item in _iter_items(args, cwd, error): |
||
| 353 | utilities.show("marking item {} as reviewed...".format(item.uid)) |
||
| 354 | item.review() |
||
| 355 | |||
| 356 | if not success: |
||
| 357 | return False |
||
| 358 | |||
| 359 | return True |
||
| 360 | |||
| 361 | |||
| 362 | def run_import(args, cwd, error, catch=True, _tree=None): |
||
| 363 | """Process arguments and run the `doorstop import` subcommand. |
||
| 364 | |||
| 365 | :param args: Namespace of CLI arguments |
||
| 366 | :param cwd: current working directory |
||
| 367 | :param error: function to call for CLI errors |
||
| 368 | :param catch: catch and log :class:`~doorstop.common.DoorstopError` |
||
| 369 | |||
| 370 | """ |
||
| 371 | document = item = None |
||
| 372 | attrs = utilities.literal_eval(args.attrs, error) |
||
| 373 | mapping = utilities.literal_eval(args.map, error) |
||
| 374 | if args.path: |
||
| 375 | if not args.prefix: |
||
| 376 | error("when [path] specified, [prefix] is also required") |
||
| 377 | elif args.document: |
||
| 378 | error("'--document' cannot be used with [path] [prefix]") |
||
| 379 | elif args.item: |
||
| 380 | error("'--item' cannot be used with [path] [prefix]") |
||
| 381 | ext = utilities.get_ext(args, error, None, None) |
||
| 382 | elif not (args.document or args.item): |
||
| 383 | error("specify [path], '--document', or '--item' to import") |
||
| 384 | |||
| 385 | with utilities.capture(catch=catch) as success: |
||
| 386 | |||
| 387 | if args.path: |
||
| 388 | |||
| 389 | # get the document |
||
| 390 | request_next_number = _request_next_number(args) |
||
| 391 | tree = _tree or _get_tree(args, cwd, |
||
| 392 | request_next_number=request_next_number) |
||
| 393 | document = tree.find_document(args.prefix) |
||
| 394 | |||
| 395 | # import items into it |
||
| 396 | msg = "importing '{}' into document {}...".format(args.path, |
||
| 397 | document) |
||
| 398 | utilities.show(msg, flush=True) |
||
| 399 | importer.import_file(args.path, document, ext, mapping=mapping) |
||
| 400 | |||
| 401 | elif args.document: |
||
| 402 | prefix, path = args.document |
||
| 403 | document = importer.create_document(prefix, path, |
||
| 404 | parent=args.parent) |
||
| 405 | elif args.item: |
||
| 406 | prefix, uid = args.item |
||
| 407 | request_next_number = _request_next_number(args) |
||
| 408 | item = importer.add_item(prefix, uid, attrs=attrs, |
||
| 409 | request_next_number=request_next_number) |
||
| 410 | if not success: |
||
| 411 | return False |
||
| 412 | |||
| 413 | if document: |
||
| 414 | utilities.show("imported document: {} ({})".format(document.prefix, |
||
| 415 | document.relpath)) |
||
| 416 | else: |
||
| 417 | assert item |
||
| 418 | utilities.show("imported item: {} ({})".format(item.uid, item.relpath)) |
||
| 419 | |||
| 420 | return True |
||
| 421 | |||
| 422 | |||
| 423 | def run_export(args, cwd, error, catch=True, auto=False, _tree=None): |
||
| 424 | """Process arguments and run the `doorstop export` subcommand. |
||
| 425 | |||
| 426 | :param args: Namespace of CLI arguments |
||
| 427 | :param cwd: current working directory |
||
| 428 | :param error: function to call for CLI errors |
||
| 429 | :param catch: catch and log :class:`~doorstop.common.DoorstopError` |
||
| 430 | |||
| 431 | :param auto: include placeholders for new items on import |
||
| 432 | |||
| 433 | """ |
||
| 434 | whole_tree = args.prefix == 'all' |
||
| 435 | ext = utilities.get_ext(args, error, '.yml', '.csv', whole_tree=whole_tree) |
||
| 436 | |||
| 437 | # Get the tree or document |
||
| 438 | with utilities.capture(catch=catch) as success: |
||
| 439 | |||
| 440 | exporter.check(ext) |
||
| 441 | tree = _tree or _get_tree(args, cwd, load=whole_tree) |
||
| 442 | if not whole_tree: |
||
| 443 | document = tree.find_document(args.prefix) |
||
| 444 | |||
| 445 | if not success: |
||
| 446 | return False |
||
| 447 | |||
| 448 | # Write to output file(s) |
||
| 449 | if args.path: |
||
| 450 | if whole_tree: |
||
| 451 | msg = "exporting tree to '{}'...".format(args.path) |
||
| 452 | utilities.show(msg, flush=True) |
||
| 453 | path = exporter.export(tree, args.path, ext, auto=auto) |
||
| 454 | else: |
||
| 455 | msg = "exporting document {} to '{}'...".format(document, |
||
| 456 | args.path) |
||
| 457 | utilities.show(msg, flush=True) |
||
| 458 | path = exporter.export(document, args.path, ext, auto=auto) |
||
| 459 | if path: |
||
| 460 | utilities.show("exported: {}".format(path)) |
||
| 461 | |||
| 462 | # Or, display to standard output |
||
| 463 | else: |
||
| 464 | if whole_tree: |
||
| 465 | error("only single documents can be displayed") |
||
| 466 | for line in exporter.export_lines(document, ext): |
||
| 467 | utilities.show(line) |
||
| 468 | |||
| 469 | return True |
||
| 470 | |||
| 471 | |||
| 472 | def run_publish(args, cwd, error, catch=True): |
||
| 473 | """Process arguments and run the `doorstop publish` subcommand. |
||
| 474 | |||
| 475 | :param args: Namespace of CLI arguments |
||
| 476 | :param cwd: current working directory |
||
| 477 | :param error: function to call for CLI errors |
||
| 478 | :param catch: catch and log :class:`~doorstop.common.DoorstopError` |
||
| 479 | |||
| 480 | """ |
||
| 481 | whole_tree = args.prefix == 'all' |
||
| 482 | ext = utilities.get_ext(args, error, '.txt', '.html', whole_tree) |
||
| 483 | |||
| 484 | # Get the tree or document |
||
| 485 | with utilities.capture(catch=catch) as success: |
||
| 486 | |||
| 487 | publisher.check(ext) |
||
| 488 | tree = _get_tree(args, cwd, load=whole_tree) |
||
| 489 | if not whole_tree: |
||
| 490 | document = tree.find_document(args.prefix) |
||
| 491 | |||
| 492 | if not success: |
||
| 493 | return False |
||
| 494 | |||
| 495 | # Set publishing arguments |
||
| 496 | kwargs = {} |
||
| 497 | if args.width: |
||
| 498 | kwargs['width'] = args.width |
||
| 499 | |||
| 500 | # Write to output file(s) |
||
| 501 | if args.path: |
||
| 502 | if whole_tree: |
||
| 503 | msg = "publishing tree to '{}'...".format(args.path) |
||
| 504 | utilities.show(msg, flush=True) |
||
| 505 | path = publisher.publish(tree, args.path, ext, **kwargs) |
||
| 506 | else: |
||
| 507 | msg = "publishing document {} to '{}'...".format(document, |
||
| 508 | args.path) |
||
| 509 | utilities.show(msg, flush=True) |
||
| 510 | path = publisher.publish(document, args.path, ext, **kwargs) |
||
| 511 | if path: |
||
| 512 | utilities.show("published: {}".format(path)) |
||
| 513 | |||
| 514 | # Or, display to standard output |
||
| 515 | else: |
||
| 516 | if whole_tree: |
||
| 517 | error("only single documents can be displayed") |
||
| 518 | for line in publisher.publish_lines(document, ext, **kwargs): |
||
| 519 | utilities.show(line) |
||
| 520 | |||
| 521 | return True |
||
| 522 | |||
| 523 | # add 28.11.2019 /11.12.2019 added findRef |
||
| 524 | View Code Duplication | def run_valMatrix(args, cwd, error, catch=True): |
|
| 525 | """ |
||
| 526 | Process arguments and run the `doorstop valMatrix` subcommand added by Peter Bauer. |
||
| 527 | |||
| 528 | :param args: Namespace of CLI arguments |
||
| 529 | :param cwd: current working directory |
||
| 530 | :param error: function to call for CLI errors |
||
| 531 | :param catch: catch and log :class:`~doorstop.common.DoorstopError` |
||
| 532 | |||
| 533 | """ |
||
| 534 | |||
| 535 | # Get document or tree |
||
| 536 | with utilities.capture(catch=catch) as success: |
||
| 537 | |||
| 538 | |||
| 539 | tree = _get_tree(args, cwd, load='all') |
||
| 540 | if not args.prefix == 'all': |
||
| 541 | document = tree.find_document(args.prefix) |
||
| 542 | |||
| 543 | if not success: |
||
| 544 | return False |
||
| 545 | |||
| 546 | |||
| 547 | if args.path: |
||
| 548 | if args.prefix == 'all': |
||
| 549 | msg = "publishing tree to '{}'...".format(args.path) |
||
| 550 | utilities.show(msg, flush=True) |
||
| 551 | valMatrix.publish_Matrix(tree, args.path) |
||
| 552 | else: |
||
| 553 | msg = "publishing document to '{}'...".format(args.path) |
||
| 554 | utilities.show(msg, flush=True) |
||
| 555 | valMatrix.publish_Matrix(document, args.path) |
||
| 556 | |||
| 557 | else: |
||
| 558 | |||
| 559 | error('There must be a tree or documetn like object given to the command!') |
||
| 560 | |||
| 561 | return True |
||
| 562 | |||
| 563 | |||
| 564 | |||
| 565 | |||
| 566 | View Code Duplication | def run_verMatrix(args, cwd, error, catch=True): |
|
| 567 | """ |
||
| 568 | Process arguments and run the `doorstop verMatrix` subcommand added by Peter Bauer. |
||
| 569 | |||
| 570 | :param args: Namespace of CLI arguments |
||
| 571 | :param cwd: current working directory |
||
| 572 | :param error: function to call for CLI errors |
||
| 573 | :param catch: catch and log :class:`~doorstop.common.DoorstopError` |
||
| 574 | |||
| 575 | """ |
||
| 576 | |||
| 577 | # Get document or tree |
||
| 578 | with utilities.capture(catch=catch) as success: |
||
| 579 | |||
| 580 | |||
| 581 | tree = _get_tree(args, cwd, load='all') |
||
| 582 | if not args.prefix == 'all': |
||
| 583 | document = tree.find_document(args.prefix) |
||
| 584 | |||
| 585 | if not success: |
||
| 586 | return False |
||
| 587 | |||
| 588 | if args.path: |
||
| 589 | if args.prefix == 'all': |
||
| 590 | msg = "publishing tree to '{}'...".format(args.path) |
||
| 591 | utilities.show(msg, flush=True) |
||
| 592 | verMatrix.publish_Matrix(tree, args.path) |
||
| 593 | else: |
||
| 594 | msg = "publishing document to '{}'...".format(args.path) |
||
| 595 | utilities.show(msg, flush=True) |
||
| 596 | verMatrix.publish_Matrix(document, args.path) |
||
| 597 | |||
| 598 | else: |
||
| 599 | error('There must be a tree or documetn like object given to the command!') |
||
| 600 | |||
| 601 | return True |
||
| 602 | |||
| 603 | |||
| 604 | |||
| 605 | |||
| 606 | def run_findRef(args, cwd, error): |
||
| 607 | """"Find references in code for given UID""" |
||
| 608 | if args.UID and args.directory: |
||
| 609 | finder.find(args, cwd) |
||
| 610 | else: |
||
| 611 | error('UID and directory must be given to find references!') |
||
| 612 | |||
| 613 | |||
| 614 | def run_ref(args, cwd, error): |
||
| 615 | """Add new reference to requirement""" |
||
| 616 | if args.UID: |
||
| 617 | tree = _get_tree(args, cwd) |
||
| 618 | item = tree.find_item(args.UID) |
||
| 619 | |||
| 620 | item.add_ref(args.reference) |
||
| 621 | |||
| 622 | |||
| 623 | else: |
||
| 624 | error:('UID must be given to add new reference!') |
||
| 625 | |||
| 626 | return True |
||
| 627 | |||
| 628 | |||
| 629 | def run_clearRef(args, cwd, error, catch=True): |
||
| 630 | """ Clear referneces if checked |
||
| 631 | |||
| 632 | :param args: Namespace of CLI arguments |
||
| 633 | :param cwd: current working directory |
||
| 634 | :param error: function to call for CLI errors |
||
| 635 | :param catch: catch and log :class:`~doorstop.common.DoorstopError` |
||
| 636 | |||
| 637 | """ |
||
| 638 | with utilities.capture(catch=catch) as success: |
||
| 639 | |||
| 640 | for item in _iter_items(args, cwd, error): |
||
| 641 | if args.referenceID == 'all': |
||
| 642 | msg = "clearing item {}'s suspect references...".format(item.uid) |
||
| 643 | else: |
||
| 644 | msg = "clearing item {}'s suspect references with ID: {}".format(item.uid, args.referenceID ) |
||
| 645 | item.clearRef(args.referenceID) |
||
| 646 | utilities.show(msg) |
||
| 647 | |||
| 648 | if not success: |
||
| 649 | return False |
||
| 650 | |||
| 651 | return True |
||
| 652 | |||
| 653 | |||
| 654 | #end add |
||
| 655 | |||
| 656 | |||
| 657 | |||
| 658 | def _request_next_number(args): |
||
| 659 | """Get the server's "next number" method if a server exists.""" |
||
| 660 | if args.force: |
||
| 661 | log.warn("creating items without the server...") |
||
| 662 | return None |
||
| 663 | else: |
||
| 664 | server.check() |
||
| 665 | return server.get_next_number |
||
| 666 | |||
| 667 | |||
| 668 | def _get_tree(args, cwd, request_next_number=None, load=False): |
||
| 669 | """Build a tree and optionally load all documents. |
||
| 670 | |||
| 671 | :param args: Namespace of CLI arguments |
||
| 672 | :param cwd: current working directory |
||
| 673 | :param request_next_number: server method to get a document's next number |
||
| 674 | :param load: force the early loading of all documents |
||
| 675 | |||
| 676 | :return: built :class:`~doorstop.core.tree.Tree` |
||
| 677 | |||
| 678 | """ |
||
| 679 | utilities.show("building tree...", flush=True) |
||
| 680 | tree = build(cwd=cwd, root=args.project, |
||
| 681 | request_next_number=request_next_number) |
||
| 682 | |||
| 683 | if load: |
||
| 684 | utilities.show("loading documents...", flush=True) |
||
| 685 | tree.load() |
||
| 686 | |||
| 687 | return tree |
||
| 688 | |||
| 689 | |||
| 690 | def _iter_items(args, cwd, error): |
||
| 691 | """Build a tree and iterate through items. |
||
| 692 | |||
| 693 | :param args: Namespace of CLI arguments |
||
| 694 | :param cwd: current working directory |
||
| 695 | :param error: function to call for CLI errors |
||
| 696 | |||
| 697 | Items are filtered to: |
||
| 698 | |||
| 699 | - `args.label` == 'all': all items |
||
| 700 | - `args.label` == document prefix: the document's items |
||
| 701 | - `args.label` == item UID: a single item |
||
| 702 | |||
| 703 | Documents and items are inferred unless flagged by: |
||
| 704 | |||
| 705 | - `args.document`: `args.label` is a prefix |
||
| 706 | - `args.item`: `args.label` is an UID |
||
| 707 | |||
| 708 | """ |
||
| 709 | # Parse arguments |
||
| 710 | if args.label == 'all': |
||
| 711 | if args.item: |
||
| 712 | error("argument -i/--item: not allowed with 'all'") |
||
| 713 | if args.document: |
||
| 714 | error("argument -d/--document: not allowed with 'all'") |
||
| 715 | |||
| 716 | # Build tree |
||
| 717 | item = None |
||
| 718 | document = None |
||
| 719 | tree = tree = _get_tree(args, cwd) |
||
| 720 | |||
| 721 | # Determine if tree, document, or item was requested |
||
| 722 | if args.label != 'all': |
||
| 723 | if not args.item: |
||
| 724 | try: |
||
| 725 | document = tree.find_document(args.label) |
||
| 726 | except common.DoorstopError as exc: |
||
| 727 | if args.document: |
||
| 728 | raise exc from None |
||
| 729 | if not document: |
||
| 730 | item = tree.find_item(args.label) |
||
| 731 | |||
| 732 | # Yield items from the requested object |
||
| 733 | if item: |
||
| 734 | yield item |
||
| 735 | elif document: |
||
| 736 | for item in document: |
||
| 737 | yield item |
||
| 738 | else: |
||
| 739 | for document in tree: |
||
| 740 | for item in document: |
||
| 741 | yield item |
||
| 742 | |||
| 743 | |||
| 744 | def _export_import(args, cwd, error, document, ext): |
||
| 745 | """Edit a document by calling export followed by import. |
||
| 746 | |||
| 747 | :param args: Namespace of CLI arguments |
||
| 748 | :param cwd: current working directory |
||
| 749 | :param error: function to call for CLI errors |
||
| 750 | :param document: :class:`~doorstop.core.document.Document` to edit |
||
| 751 | :param ext: extension for export format |
||
| 752 | |||
| 753 | """ |
||
| 754 | # Export the document to file |
||
| 755 | args.prefix = document.prefix |
||
| 756 | path = "{}-{}{}".format(args.prefix, int(time.time()), ext) |
||
| 757 | args.path = path |
||
| 758 | get('export')(args, cwd, error, catch=False, auto=True, |
||
| 759 | _tree=document.tree) |
||
| 760 | |||
| 761 | # Open the exported file |
||
| 762 | editor.edit(path, tool=args.tool) |
||
| 763 | |||
| 764 | # Import the file to the same document |
||
| 765 | if utilities.ask("import from '{}'?".format(path)): |
||
| 766 | args.attrs = {} |
||
| 767 | args.map = {} |
||
| 768 | get('import')(args, cwd, error, catch=False, _tree=document.tree) |
||
| 769 | common.delete(path) |
||
| 770 | else: |
||
| 771 | utilities.show("import canceled") |
||
| 772 | if utilities.ask("delete '{}'?".format(path)): |
||
| 773 | common.delete(path) |
||
| 774 | else: |
||
| 775 | msg = "to manually import: doorstop import {0}".format(path) |
||
| 776 | utilities.show(msg) |
||
| 777 |