Grcov report - task_dependency.rs

1

    use serde::Deserialize;

2

3

    use super::TaskContext;

4

5

    /// This struct represents a task dependency. A task can depend on other tasks.

6

    /// If a task depends on another task, the dependent task must be executed before

7

    /// the dependent task.

8

    #[derive(Debug, Deserialize)]

9

    pub struct TaskDependencyArgs {

10

      /// The name of the task to depend on

11

      pub name: String,

12

    }

13

14

    #[derive(Debug, Deserialize)]

15

    #[serde(untagged)]

16

    pub enum TaskDependency {

17

      String(String),

18

      TaskDependency(Box<TaskDependencyArgs>),

19

    }

20

21

    impl TaskDependency {

22

      pub fn run(&self, context: &TaskContext) -> anyhow::Result<()> {

23

        match self {

24

          TaskDependency::String(name) => self.execute(context, name),

25

          TaskDependency::TaskDependency(args) => args.execute(context),

26

        }

27

      }

28

29

      fn execute(&self, context: &TaskContext, task_name: &str) -> anyhow::Result<()> {

30

        assert!(!task_name.is_empty());

31

32

        let task = context

33

          .task_root

34

          .tasks

35

          .get(task_name)

36

          .ok_or_else(|| anyhow::anyhow!("Task not found"))?;

37

38

        log::trace!("Task: {:?}", task);

39

40

        {

41

          let mut stack = context

42

            .execution_stack

43

            .lock()

44

            .map_err(|e| anyhow::anyhow!("Failed to lock execution stack - {}", e))?;

45

46

          if stack.contains(task_name) {

47

            anyhow::bail!("Circular dependency detected - {}", task_name);

48

          }

49

50

          stack.insert(task_name.into());

51

        }

52

53

        let mut context = TaskContext::from_context(context);

54

        task.run(&mut context)?;

55

56

        Ok(())

57

      }

58

    }

59

60

    impl TaskDependencyArgs {

61
20

      pub fn execute(&self, context: &TaskContext) -> anyhow::Result<()> {

62
20

        assert!(!self.name.is_empty());

63

64
20

        let task_name: &str = &self.name;

65
20

        let task = context

66
20

          .task_root

67
20

          .tasks

68
20

          .get(task_name)

69
20

          .ok_or_else(|| anyhow::anyhow!("Task not found"))?;

70

71
20

        log::trace!("Task: {:?}", task);

72

73

        {

74
20

          let mut stack = context

75
20

            .execution_stack

76
20

            .lock()

77
20

            .map_err(|e| anyhow::anyhow!("Failed to lock execution stack - {}", e))?;

78

79
20

          if stack.contains(task_name) {

80

            anyhow::bail!("Circular dependency detected - {}", task_name);

81
20

          }

82
20

83
20

          stack.insert(task_name.into());

84
20

        }

85
20

86
20

        let mut context = TaskContext::from_context(context);

87
20

        task.run(&mut context)?;

88

89
20

        Ok(())

90
20

      }

91

    }

92

93

    #[cfg(test)]

94

    mod test {

95

      use hashbrown::HashMap;

96

      use std::sync::Arc;

97

98

      use crate::schema::{

99

        Task,

100

        TaskRoot,

101

      };

102

103

      use super::*;

104

105

      #[test]

106
20

      fn test_task_dependency_1() -> anyhow::Result<()> {

107
20

        let yaml = "

108
20

          name: task1

109
20

        ";

110

111
20

        let task_dependency = serde_yaml::from_str::<TaskDependency>(yaml)?;

112
20

        if let TaskDependency::TaskDependency(args) = task_dependency {

113
20

          assert_eq!(args.name, "task1");

114

        } else {

115

          panic!("Expected TaskDependency::TaskDependency");

116

        }

117

118
20

        Ok(())

119
20

      }

120

121

      #[test]

122
20

      fn test_task_dependency_2() -> anyhow::Result<()> {

123
20

        let yaml = "\"task1\"";

124

125
20

        let task_dependency = serde_yaml::from_str::<TaskDependency>(yaml)?;

126
20

        if let TaskDependency::String(name) = task_dependency {

127
20

          assert_eq!(name, "task1");

128

        } else {

129

          panic!("Expected TaskDependency::TaskString");

130

        }

131

132
20

        Ok(())

133
20

      }

134

135

      #[test]

136
20

      fn test_task_dependency_3() -> anyhow::Result<()> {

137
20

        let yaml = "\"\"";

138

139
20

        let task_dependency = serde_yaml::from_str::<TaskDependency>(yaml)?;

140
20

        if let TaskDependency::String(name) = task_dependency {

141
20

          assert_eq!(name, "");

142

        } else {

143

          panic!("Expected TaskDependency::TaskString");

144

        }

145

146
20

        Ok(())

147
20

      }

148

149

      #[test]

150
20

      fn test_task_dependency_4() -> anyhow::Result<()> {

151
20

        let yaml = "

152
20

          name:

153
20

        ";

154

155
20

        let task_dependency = serde_yaml::from_str::<TaskDependencyArgs>(yaml)?;

156
20

        assert_eq!(task_dependency.name, "");

157

158
20

        Ok(())

159
20

      }

160

161

      #[test]

162
20

      fn test_task_dependency_5() -> anyhow::Result<()> {

163
20

        let yaml = "

164
20

          name: task_a

165
20

        ";

166
20

167
20

        let task_yaml = "

168
20

          commands:

169
20

            - command: echo 1

170
20

              verbose: false

171
20

        ";

172

173
20

        let task = serde_yaml::from_str::<Task>(task_yaml)?;

174
20

        let mut hm = HashMap::new();

175
20

        hm.insert("task_a".into(), task);

176
20

177
20

        let root = Arc::new(TaskRoot::from_hashmap(hm));

178
20

        let task_dependency = serde_yaml::from_str::<TaskDependencyArgs>(yaml)?;

179
20

        let result = task_dependency.execute(&TaskContext::empty_with_root(root));

180
20

        assert!(result.is_ok());

181

182
20

        Ok(())

183
20

      }

184

    }