Coverage for putki/cli.py: 0.00%

56 statements  

« prev     ^ index     » next       coverage.py v7.4.1, created at 2024-02-04 22:07:46 +00:00

1"""Command line interface for pipeline (Finnish: putki) - discovering and executing a specific task description.""" 

2 

3import logging 

4import pathlib 

5import sys 

6 

7import typer 

8 

9import putki.api as api 

10from putki import APP_NAME, DEFAULT_STRUCTURE_NAME, DEFAULT_STRUCTURES_NAME, QUIET, __version__ as APP_VERSION, log 

11 

12app = typer.Typer( 

13 add_completion=False, 

14 context_settings={'help_option_names': ['-h', '--help']}, 

15 no_args_is_help=True, 

16) 

17 

18DocumentRoot = typer.Option( 

19 '', 

20 '-d', 

21 '--document-root', 

22 help='Root of the document tree to visit. Optional\n(default: positional tree root value)', 

23) 

24 

25StructureName = typer.Option( 

26 DEFAULT_STRUCTURE_NAME, 

27 '-s', 

28 '--structure', 

29 help='structure mapping file (default: {DEFAULT_STRUCTURE_NAME})', 

30) 

31 

32TargetName = typer.Option( 

33 '', 

34 '-t', 

35 '--target', 

36 help='target document key', 

37) 

38 

39FacetName = typer.Option( 

40 '', 

41 '-f', 

42 '--facet', 

43 help='facet key of target document', 

44) 

45 

46Verbosity = typer.Option( 

47 False, 

48 '-v', 

49 '--verbose', 

50 help='Verbose output (default is False)', 

51) 

52 

53Strictness = typer.Option( 

54 False, 

55 '-s', 

56 '--strict', 

57 help='Ouput noisy warnings on console (default is False)', 

58) 

59 

60OutputPath = typer.Option( 

61 '', 

62 '-o', 

63 '--output-path', 

64 help='Path to output unambiguous content to - like when ejecting a template', 

65) 

66 

67StructuresName = typer.Option( 

68 DEFAULT_STRUCTURES_NAME, 

69 # '', 

70 '--structures', 

71 help='structures mapping file (default: {DEFAULT_STRUCTURES_NAME})', 

72) 

73 

74ComponentFolderName = typer.Option( # TODO: prepare later for additional intermediates 

75 'component', 

76 # '', 

77 '--component-folder-name', 

78 help='component folder name (default: component)', 

79) 

80 

81 

82@app.callback(invoke_without_command=True) 

83def callback( 

84 version: bool = typer.Option( 

85 False, 

86 '-V', 

87 '--version', 

88 help='Display the application version and exit', 

89 is_eager=True, 

90 ) 

91) -> None: 

92 """ 

93 Pipeline (Finnish: putki) - discovering and executing a specific task description. 

94 """ 

95 if version: 

96 typer.echo(f'{APP_NAME} version {APP_VERSION}') 

97 raise typer.Exit() 

98 

99 

100def _verify_call_vector( 

101 doc_root: str, doc_root_pos: str, verbose: bool, strict: bool 

102) -> tuple[int, str, str, dict[str, bool]]: 

103 """DRY""" 

104 doc = doc_root.strip() 

105 if not doc and doc_root_pos: 

106 doc = doc_root_pos 

107 if not doc: 

108 print('Document tree root required', file=sys.stderr) 

109 return 2, 'Document tree root required', '', {} 

110 

111 doc_root_path = pathlib.Path(doc) 

112 if doc_root_path.exists(): 

113 if not doc_root_path.is_dir(): 

114 print(f'requested tree root at ({doc}) is not a folder', file=sys.stderr) 

115 return 2, f'requested tree root at ({doc}) is not a folder', '', {} 

116 else: 

117 print(f'requested tree root at ({doc}) does not exist', file=sys.stderr) 

118 return 2, f'requested tree root at ({doc}) does not exist', '', {} 

119 

120 options = { 

121 'quiet': QUIET and not verbose and not strict, 

122 'strict': strict, 

123 'verbose': verbose, 

124 } 

125 if verbose: 

126 logging.getLogger().setLevel(logging.DEBUG) 

127 return 0, '', doc, options 

128 

129 

130@app.command('tasks') 

131def verify_tasks( # noqa 

132 doc_root_pos: str = typer.Argument(''), 

133 doc_root: str = DocumentRoot, 

134 structure: str = StructureName, 

135 target: str = TargetName, 

136 facet: str = FacetName, 

137 verbose: bool = Verbosity, 

138 strict: bool = Strictness, 

139) -> int: 

140 """ 

141 Verify the structure definition against the file system. 

142 """ 

143 code, message, doc, options = _verify_call_vector(doc_root, doc_root_pos, verbose, strict) 

144 if code: 

145 log.error(message) 

146 return code 

147 

148 return sys.exit( 

149 api.verify_tasks(doc_root=doc, structure_name=structure, target_key=target, facet_key=facet, options=options) 

150 ) 

151 

152 

153@app.command('structures') 

154def verify_structures( # noqa 

155 doc_root_pos: str = typer.Argument(''), 

156 doc_root: str = DocumentRoot, 

157 structures: str = StructuresName, 

158 component: str = ComponentFolderName, 

159 verbose: bool = Verbosity, 

160 strict: bool = Strictness, 

161) -> int: 

162 """ 

163 Verify the structure definition against the file system. 

164 """ 

165 code, message, doc, options = _verify_call_vector(doc_root, doc_root_pos, verbose, strict) 

166 if code: 

167 log.error(message) 

168 return code 

169 

170 return sys.exit( 

171 api.verify_structures(doc_root=doc, structures_name=structures, component=component, options=options) 

172 ) 

173 

174 

175@app.command('version') 

176def app_version() -> None: 

177 """ 

178 Display the application version and exit. 

179 """ 

180 callback(True)