Coverage for tsfpga/svn_utils.py: 67%

49 statements  

« prev     ^ index     » next       coverage.py v6.5.0, created at 2022-11-29 20:01 +0000

1# -------------------------------------------------------------------------------------------------- 

2# Copyright (c) Lukas Vik. All rights reserved. 

3# 

4# This file is part of the tsfpga project, a project platform for modern FPGA development. 

5# https://tsfpga.com 

6# https://gitlab.com/tsfpga/tsfpga 

7# -------------------------------------------------------------------------------------------------- 

8 

9# Standard libraries 

10import re 

11import subprocess 

12 

13# First party libraries 

14from tsfpga.system_utils import file_is_in_directory 

15 

16 

17def get_svn_revision_information(cwd=None): 

18 check_that_svn_commands_are_available(cwd) 

19 result = f"r{get_svn_revision(cwd)}" 

20 if svn_local_changes_are_present(cwd): 

21 result += " (local changes present)" 

22 return result 

23 

24 

25def svn_commands_are_available(cwd=None): 

26 try: 

27 get_svn_revision(cwd) 

28 except (subprocess.CalledProcessError, FileNotFoundError): 

29 return False 

30 return True 

31 

32 

33def check_that_svn_commands_are_available(cwd=None): 

34 if not svn_commands_are_available(cwd): 

35 mesg = ( 

36 "Could not run svn. Is the command available on PATH? Is the script called from a repo?" 

37 ) 

38 raise RuntimeError(mesg) 

39 

40 

41def get_svn_revision(cwd=None): 

42 command = ["svn", "info", "--show-item", "revision"] 

43 output = subprocess.check_output(command, cwd=cwd, universal_newlines=True) 

44 # Remove trailing newline 

45 return int(output.strip()) 

46 

47 

48def svn_local_changes_are_present(cwd=None): 

49 """ 

50 Return true if the repo contains changes that have been made after the last commit. 

51 Info from here: https://rubyinrails.com/2014/01/11/svn-command-to-check-modified-files/ 

52 """ 

53 command = ["svn", "status"] 

54 output = subprocess.check_output(command, cwd=cwd, universal_newlines=True) 

55 # Status code for file Added, Deleted, Modified, in Conflict or missing 

56 regexp = re.compile(r"\n[ADMC!] ") 

57 return regexp.search(output) is not None 

58 

59 

60RE_SVN_STATUS_LINE = re.compile(r"^.+\d+\s+\d+\s+\S+\s+(\S+)$") 

61 

62 

63def find_svn_files( 

64 directory, 

65 excludes=None, 

66 file_endings_include=None, 

67 file_endings_avoid=None, 

68): 

69 """ 

70 Find files that are checked in to SVN. It runs "svn status" rather than "svn ls". This means 

71 that it is a local operation, that does not require credentials or any connection with 

72 an SVN server. 

73 

74 Arguments: 

75 directory (pathlib.Path): Search in this directory. 

76 excludes (list(pathlib.Path)): These files and folders will not be included. 

77 file_endings_include (str or tuple(str)). Only files with these endings will be included. 

78 file_endings_avoid (str or tuple(str)): String or tuple of strings. Files with these endings 

79 will not be included. 

80 

81 Returns: 

82 list(pathlib.Path): The files that are available in SVN. 

83 """ 

84 excludes = [] if excludes is None else [exclude.resolve() for exclude in excludes] 

85 

86 command = ["svn", "status", "-v"] 

87 output = subprocess.check_output(command, cwd=directory, universal_newlines=True) 

88 for line in output.split("\n"): 

89 match = RE_SVN_STATUS_LINE.match(line) 

90 if not match: 

91 continue 

92 

93 svn_file = match.group(1) 

94 file_path = directory / svn_file 

95 

96 # Make sure concatenation of relative paths worked 

97 assert file_path.exists(), file_path 

98 

99 if file_path.is_dir(): 

100 continue 

101 

102 if file_endings_include is not None and not file_path.name.endswith(file_endings_include): 

103 continue 

104 

105 if file_endings_avoid is not None and file_path.name.endswith(file_endings_avoid): 

106 continue 

107 

108 if file_is_in_directory(file_path, excludes): 

109 continue 

110 

111 yield file_path