Coverage for e2xgrader/exchange/release_assignment.py: 20%

46 statements  

« prev     ^ index     » next       coverage.py v7.4.2, created at 2024-03-14 13:22 +0100

1import os 

2import shutil 

3from stat import ( 

4 S_IRGRP, 

5 S_IROTH, 

6 S_IRUSR, 

7 S_ISGID, 

8 S_IWGRP, 

9 S_IWOTH, 

10 S_IWUSR, 

11 S_IXGRP, 

12 S_IXOTH, 

13 S_IXUSR, 

14) 

15 

16from nbgrader.exchange.default import ExchangeReleaseAssignment 

17 

18from .exchange import E2xExchange 

19 

20 

21class E2xExchangeReleaseAssignment(E2xExchange, ExchangeReleaseAssignment): 

22 def init_dest(self): 

23 if self.coursedir.course_id == "": 

24 self.fail("No course id specified. Re-run with --course flag.") 

25 

26 self.course_path = os.path.join(self.root, self.coursedir.course_id) 

27 self.outbound_path = os.path.join(self.course_path, self.outbound_directory) 

28 self.inbound_path = os.path.join(self.course_path, self.inbound_directory) 

29 

30 # 0755 

31 # groupshared: +2040 

32 self.ensure_directory( 

33 self.course_path, 

34 S_IRUSR 

35 | S_IWUSR 

36 | S_IXUSR 

37 | S_IRGRP 

38 | S_IXGRP 

39 | S_IROTH 

40 | S_IXOTH 

41 | ((S_ISGID | S_IWGRP) if self.coursedir.groupshared else 0), 

42 ) 

43 

44 if self.personalized_outbound: 

45 # the dest path is <exchange_root>/personalized-outbound/<username>/<assignment_id> 

46 # <username> is created by either grader via formgrader or student during spawning 

47 # <username> here is deterministic and has to be in the release directory 

48 self.dest_path = self.outbound_path 

49 

50 # 0777 for personalized_outbound 

51 # groupshared: +2040 

52 self.ensure_directory( 

53 self.dest_path, 

54 S_IRUSR 

55 | S_IWUSR 

56 | S_IXUSR 

57 | S_IRGRP 

58 | S_IWGRP 

59 | S_IXGRP 

60 | S_IROTH 

61 | S_IWOTH 

62 | S_IXOTH 

63 | ((S_ISGID | S_IWGRP) if self.coursedir.groupshared else 0), 

64 ) 

65 else: 

66 self.dest_path = os.path.join( 

67 self.outbound_path, self.coursedir.assignment_id 

68 ) 

69 

70 # 0755 

71 # groupshared: +2040 

72 self.ensure_directory( 

73 self.outbound_path, 

74 S_IRUSR 

75 | S_IWUSR 

76 | S_IXUSR 

77 | S_IRGRP 

78 | S_IXGRP 

79 | S_IROTH 

80 | S_IXOTH 

81 | ((S_ISGID | S_IWGRP) if self.coursedir.groupshared else 0), 

82 ) 

83 

84 # 0733 with set GID so student submission will have the instructors group 

85 # groupshared: +0040 

86 self.ensure_directory( 

87 self.inbound_path, 

88 S_ISGID 

89 | S_IRUSR 

90 | S_IWUSR 

91 | S_IXUSR 

92 | S_IWGRP 

93 | S_IXGRP 

94 | S_IWOTH 

95 | S_IXOTH 

96 | (S_IRGRP if self.coursedir.groupshared else 0), 

97 ) 

98 

99 def copy_files(self): 

100 if self.personalized_outbound: 

101 # check available users under course_path/<assignmet_dir>/<username> 

102 user_list = [ 

103 user 

104 for user in os.listdir(self.src_path) 

105 if os.path.isdir(os.path.join(self.src_path, user)) 

106 and user != self.coursedir.assignment_id 

107 ] 

108 for user in user_list: 

109 released_assignment_root = os.path.join(self.dest_path, user) 

110 released_user_assignment = os.path.join( 

111 released_assignment_root, self.coursedir.assignment_id 

112 ) 

113 if os.path.isdir(released_user_assignment): 

114 shutil.rmtree(released_user_assignment) 

115 

116 src_assignment = os.path.join(self.src_path, user) 

117 if os.path.isdir(src_assignment): 

118 self.log.info(f"Source: {src_assignment}") 

119 self.log.info(f"Destination: {released_user_assignment}") 

120 self.do_copy(src_assignment, released_user_assignment) 

121 self.set_released_assignment_perm(released_user_assignment) 

122 else: 

123 self.log.info(f"Src assignment not found: {src_assignment}") 

124 else: 

125 if os.path.isdir(self.dest_path): 

126 if self.force: 

127 self.log.info( 

128 "Overwriting files: {} {}".format( 

129 self.coursedir.course_id, self.coursedir.assignment_id 

130 ) 

131 ) 

132 shutil.rmtree(self.dest_path) 

133 else: 

134 self.fail( 

135 "Destination already exists, add --force to overwrite: {} {}".format( 

136 self.coursedir.course_id, self.coursedir.assignment_id 

137 ) 

138 ) 

139 

140 self.log.info(f"Source: {self.src_path}") 

141 self.log.info(f"Destination: {self.dest_path}") 

142 self.do_copy(self.src_path, self.dest_path) 

143 self.set_released_assignment_perm(self.dest_path) 

144 self.log.info( 

145 "Released as: {} {}".format( 

146 self.coursedir.course_id, self.coursedir.assignment_id 

147 ) 

148 ) 

149 

150 def set_released_assignment_perm(self, path): 

151 self.set_perms( 

152 path, 

153 fileperms=( 

154 S_IRUSR 

155 | S_IWUSR 

156 | S_IRGRP 

157 | S_IROTH 

158 | (S_IWGRP if self.coursedir.groupshared else 0) 

159 ), 

160 dirperms=( 

161 S_IRUSR 

162 | S_IWUSR 

163 | S_IXUSR 

164 | S_IRGRP 

165 | S_IXGRP 

166 | S_IROTH 

167 | S_IXOTH 

168 | ((S_ISGID | S_IWGRP) if self.coursedir.groupshared else 0) 

169 ), 

170 )