Coverage for src/somesy/cli/sync.py: 95%

39 statements  

« prev     ^ index     » next       coverage.py v7.2.7, created at 2023-08-10 14:33 +0000

1"""Sync command for somesy.""" 

2import logging 

3from pathlib import Path 

4from typing import Optional 

5 

6import typer 

7from rich.pretty import pretty_repr 

8 

9from somesy.commands import sync as sync_command 

10from somesy.core.core import discover_input 

11from somesy.core.log import SomesyLogLevel, get_log_level, set_log_level 

12from somesy.core.models import SomesyConfig, SomesyInput 

13 

14from .util import wrap_exceptions 

15 

16logger = logging.getLogger("somesy") 

17 

18app = typer.Typer() 

19 

20 

21@app.callback(invoke_without_command=True) 

22@wrap_exceptions 

23def sync( 

24 input_file: Path = typer.Option( 

25 None, 

26 "--input-file", 

27 "-i", 

28 exists=False, 

29 file_okay=True, 

30 dir_okay=False, 

31 writable=True, 

32 readable=True, 

33 resolve_path=True, 

34 help="Somesy input file path (default: .somesy.toml)", 

35 ), 

36 no_sync_pyproject: bool = typer.Option( 

37 None, 

38 "--no-sync-pyproject", 

39 "-P", 

40 help="Do not sync pyproject.toml file (default: False)", 

41 ), 

42 pyproject_file: Path = typer.Option( 

43 None, 

44 "--pyproject-file", 

45 "-p", 

46 exists=True, 

47 file_okay=True, 

48 dir_okay=False, 

49 writable=True, 

50 readable=True, 

51 resolve_path=True, 

52 help="Existing pyproject.toml file path (default: pyproject.toml)", 

53 ), 

54 no_sync_package_json: bool = typer.Option( 

55 None, 

56 "--sync-package-json", 

57 "-J", 

58 help="Do not sync package.json file (default: False)", 

59 ), 

60 package_json_file: Path = typer.Option( 

61 None, 

62 "--package-json-file", 

63 "-j", 

64 exists=True, 

65 file_okay=True, 

66 dir_okay=False, 

67 writable=True, 

68 readable=True, 

69 resolve_path=True, 

70 help="Existing package.json file path (default: package.json)", 

71 ), 

72 no_sync_cff: bool = typer.Option( 

73 None, 

74 "--no-sync-cff", 

75 "-C", 

76 help="Do not sync CITATION.cff file (default: False)", 

77 ), 

78 cff_file: Path = typer.Option( 

79 None, 

80 "--cff-file", 

81 "-c", 

82 exists=False, 

83 file_okay=True, 

84 dir_okay=False, 

85 writable=True, 

86 readable=True, 

87 resolve_path=True, 

88 help="CITATION.cff file path (default: CITATION.cff)", 

89 ), 

90 no_sync_codemeta: bool = typer.Option( 

91 None, 

92 "--no-sync-codemeta", 

93 "-M", 

94 help="Do not sync codemeta.json file", 

95 ), 

96 codemeta_file: Path = typer.Option( 

97 None, 

98 "--codemeta-file", 

99 "-m", 

100 exists=False, 

101 file_okay=True, 

102 dir_okay=False, 

103 writable=True, 

104 readable=True, 

105 resolve_path=True, 

106 help="Custom codemeta.json file path", 

107 ), 

108): 

109 """Sync project metadata input with metadata files.""" 

110 # --------------- 

111 # config from CLI (merged with possibly set CLI flags for logging) 

112 passed_cli_args = { 

113 k: v 

114 for k, v in dict( 

115 input_file=discover_input(input_file), 

116 no_sync_cff=no_sync_cff, 

117 cff_file=cff_file, 

118 no_sync_pyproject=no_sync_pyproject, 

119 pyproject_file=pyproject_file, 

120 no_sync_package_json=no_sync_package_json, 

121 package_json_file=package_json_file, 

122 no_sync_codemeta=no_sync_codemeta, 

123 codemeta_file=codemeta_file, 

124 ).items() 

125 if v is not None 

126 } 

127 somesy_conf = SomesyConfig(**passed_cli_args) 

128 

129 # cli_log_level is None if the user did not pass a log level (-> "default") 

130 cli_log_level: Optional[SomesyLogLevel] = get_log_level() 

131 

132 if cli_log_level is not None: 

133 # update log level flags if cli log level was set 

134 somesy_conf.update_log_level(cli_log_level) 

135 

136 somesy_input: SomesyInput = somesy_conf.get_input() 

137 

138 if cli_log_level is None: 

139 # no cli log level -> set it according to the loaded configuration 

140 set_log_level(somesy_input.config.log_level()) 

141 

142 logger.debug( 

143 f"Combined config (Defaults + File + CLI):\n{pretty_repr(somesy_input.config)}" 

144 ) 

145 # -------- 

146 run_sync(somesy_input) 

147 

148 

149def run_sync(somesy_input: SomesyInput): 

150 """Write log messages and run synchronization based on passed config.""" 

151 conf = somesy_input.config 

152 logger.info("[bold green]Synchronizing project metadata...[/bold green]") 

153 logger.info("Files to sync:") 

154 if not conf.no_sync_pyproject: 

155 logger.info( 

156 f" - [italic]pyproject.toml[/italic]:\t[grey]{conf.pyproject_file}[/grey]" 

157 ) 

158 if not conf.no_sync_package_json: 

159 logger.info( 

160 f" - [italic]package.json[/italic]:\t[grey]{conf.package_json_file}[/grey]" 

161 ) 

162 if not conf.no_sync_cff: 

163 logger.info(f" - [italic]CITATION.cff[/italic]:\t[grey]{conf.cff_file}[/grey]") 

164 if not conf.no_sync_codemeta: 

165 logger.info( 

166 f" - [italic]codemeta.json[/italic]:\t[grey]{conf.codemeta_file}[/grey]\n" 

167 ) 

168 # ---- 

169 sync_command(somesy_input) 

170 # ---- 

171 logger.info("[bold green]Metadata synchronization completed.[/bold green]")