Repository: cristianoliveira/funzzy (language: rust)

Issue:
feat: enable running a task by name or index 



Discussion / hints:

Fix patch:
diff --git a/Cargo.lock b/Cargo.lock
index dc5603c..4b14d17 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -83,7 +83,7 @@ checksum = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7"
 
 [[package]]
 name = "funzzy"
-version = "0.5.0"
+version = "0.6.0"
 dependencies = [
  "docopt",
  "glob",
diff --git a/Cargo.toml b/Cargo.toml
index ffa07fa..a16bdc9 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "funzzy"
-version = "0.5.0"
+version = "0.6.0"
 authors = ["Cristian Oliveira <me@cristianoliveira.com>"]
 description = "Yet another fancy watcher inspired by entr."
 license = "MIT"
diff --git a/Makefile b/Makefile
index 501c4e8..94f37f6 100644
--- a/Makefile
+++ b/Makefile
@@ -10,8 +10,14 @@ tests: ## Execute all the tests
 build: tests ## Execute all the tests and build funzzy binary
 	@cargo test
 
+.PHONY: integration-cleanup
+integration-cleanup:
+	rm -rf target && \
+		rm -rf tests/integration/workdir && \
+		rm -f tests/integration/funzzy
+
 .PHONY: integration
-integration:
+integration: integration-cleanup
 	@bash tests/integration/runner.sh
 
 .PHONY: install
diff --git a/src/cli/watch.rs b/src/cli/watch.rs
index 3e0842c..bd9b1cc 100644
--- a/src/cli/watch.rs
+++ b/src/cli/watch.rs
@@ -130,6 +130,20 @@ impl Watches {
         Watches { rules: rules }
     }
 
+    pub fn filter(&self, predicate: impl Fn(&rules::Rules) -> bool) -> Self {
+        let targeted = self.rules
+            .iter()
+            .filter(|x| predicate(*x))
+            .map(|x| x.clone())
+            .collect::<Vec<rules::Rules>>();
+
+        if targeted.len() == 0 {
+            panic!("No rules found for the given filter")
+        }
+
+        Watches { rules: targeted }
+    }
+
     fn load_from_str(plain_text: &str) -> Self {
         Watches {
             rules: rules::from_yaml(plain_text),
diff --git a/src/main.rs b/src/main.rs
index 146940c..81dd61f 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -36,6 +36,7 @@ Usage:
 Options:
   run                  Execute command in a given interval (seconds)
   --config=<cfgfile>   Use given config file.
+  --target=<task>      Execute only the given task target.
   -h --help            Shows this message.
   -v --version         Shows version.
   -V                   Use verbose output.
@@ -55,6 +56,8 @@ pub struct Args {
 
     // options
     pub flag_config: String,
+    pub flag_target: String,
+
     pub flag_c: bool,
     pub flag_h: bool,
     pub flag_v: bool,
@@ -99,12 +102,24 @@ fn main() {
 
         Args { ref flag_config, .. } if !flag_config.is_empty() => {
             let watches = Watches::from(&from_file(&args.flag_config));
-            execute(WatchCommand::new(watches, args.flag_V));
+            if !args.flag_target.is_empty() {
+                execute(WatchCommand::new(
+                        watches.filter(|r| r.name.contains(&args.flag_target)),
+                            args.flag_V));
+            } else {
+                execute(WatchCommand::new(watches, args.flag_V));
+            }
         }
 
         _ => {
             let watches = Watches::from(&from_file(cli::watch::DEFAULT_FILENAME));
-            execute(WatchCommand::new(watches, args.flag_V));
+            if !args.flag_target.is_empty() {
+                execute(WatchCommand::new(
+                        watches.filter(|r| r.name.contains(&args.flag_target)),
+                            args.flag_V));
+            } else {
+                execute(WatchCommand::new(watches, args.flag_V));
+            }
         }
     }
 }
diff --git a/src/rules.rs b/src/rules.rs
index 167d370..c433637 100644
--- a/src/rules.rs
+++ b/src/rules.rs
@@ -7,8 +7,10 @@ use self::glob::Pattern;
 use self::yaml_rust::Yaml;
 use self::yaml_rust::YamlLoader;
 
-#[derive(Debug)]
+#[derive(Debug, Clone)]
 pub struct Rules {
+    pub name: String,
+
     commands: Vec<String>,
     watch_patterns: Vec<String>,
     ignore_patterns: Vec<String>,
@@ -17,12 +19,14 @@ pub struct Rules {
 
 impl Rules {
     pub fn new(
+        name: String,
         commands: Vec<String>,
         watches: Vec<String>,
         ignores: Vec<String>,
         run_on_init: bool,
     ) -> Self {
         Rules {
+            name: name,
             commands: commands,
             watch_patterns: watches,
             ignore_patterns: ignores,
@@ -35,6 +39,7 @@ impl Rules {
         yaml::validate(yaml, "change");
 
         Rules {
+            name: yaml::extract_strings(&yaml["name"])[0].clone(),
             commands: yaml::extract_strings(&yaml["run"]),
             watch_patterns: yaml::extract_strings(&yaml["change"]),
             ignore_patterns: yaml::extract_strings(&yaml["ignore"]),
@@ -78,7 +83,7 @@ pub fn from_string(patterns: String, command: &String) -> Vec<Rules> {
         .filter(|line| line.len() > 1)
         .map(|line| format!("**/{}", &line[2..]))
         .collect();
-    vec![Rules::new(vec![command.clone()], watches, vec![], false)]
+    vec![Rules::new("unnamed".to_owned(),vec![command.clone()], watches, vec![], false)]
 }
 
 fn pattern(pattern: &str) -> Pattern {


Test patch:
diff --git a/tests/integration/.tests.yaml b/tests/integration/.tests.yaml
index 06ef5fb..8603580 100644
--- a/tests/integration/.tests.yaml
+++ b/tests/integration/.tests.yaml
@@ -4,6 +4,6 @@
 # list here all the events and the commands that it should execute
 
 - name: run my test
-  run: "sh runner.sh"
+  run: "bash runner.sh"
   change: "specs/**"
   run_on_init: true
diff --git a/tests/integration/functions.sh b/tests/integration/functions.sh
index acea2ae..01cdebe 100644
--- a/tests/integration/functions.sh
+++ b/tests/integration/functions.sh
@@ -7,7 +7,7 @@ function test() {
 }
 
 function cleanup() {
-  rm -rf "$TEST_DIR/workdir"
+  rm -rf workdir
   echo "kill funzzy $FUNZZY_PID"
   kill "$FUNZZY_PID"
 }
@@ -26,9 +26,33 @@ function assert_file_contains() {
     if grep -q "$2" "$1"; then
       success=1
       break
+    else
+      echo "Attempt failed: file $1 does not contain $2"
+      echo "Attempt $i..."
+      sleep 5
+    fi
+  done
+
+  if [ $success -eq 0 ]; then
+    echo "ERROR: file $1 does not contain $2"
+    echo "file content:"
+    echo "$(cat $1)"
+    exit 1
+  fi
+}
+
+function assert_file_not_contains() {
+  local success=0
+  for i in {1..10}
+  do
+    if grep -q "$2" "$1"; then
+      echo "Attempt failed: file $1 does contain $2"
+      echo "Attempt $i..."
+      sleep 5
+    else
+      success=1
+      break
     fi
-    echo "Attempt $i..."
-    sleep 5
   done
 
   if [ $success -eq 0 ]; then
diff --git a/tests/integration/runner.sh b/tests/integration/runner.sh
index ef8525d..ba7af77 100644
--- a/tests/integration/runner.sh
+++ b/tests/integration/runner.sh
@@ -6,16 +6,15 @@ export TEST_DIR="$PWD/tests/integration"
 export HELPERS="$TEST_DIR/functions.sh"
 export WORKDIR="$TEST_DIR/workdir"
 
-# funzzy binary is not present build
-if [ ! -f $PWD/target/release/funzzy ]; then
-  echo "Building funzzy"
-  cargo build --release
-fi
-
+echo "Building funzzy"
+cargo build --release
 cp target/release/funzzy $TEST_DIR/funzzy
 
 PATH=$PATH:tests/integration
 
+$TEST_DIR/funzzy --version
+$TEST_DIR/funzzy --help
+
 for spec in $TEST_DIR/specs/*; do
   echo "Running $spec"
   bash "$spec" && echo "result: passed" || exit 1
diff --git a/tests/integration/specs/run-target-task-test.sh b/tests/integration/specs/run-target-task-test.sh
new file mode 100644
index 0000000..45205e0
--- /dev/null
+++ b/tests/integration/specs/run-target-task-test.sh
@@ -0,0 +1,36 @@
+#!/usr/bin/env bash
+source "$HELPERS"
+
+test "allows to run a target task"
+target="second command"
+config_file="$WORKDIR/target.yaml"
+
+echo "
+- name: run first command
+  run: \"echo '{{test}} command' | sed  s/test/first/g\"
+  change: \"$WORKDIR/**\"
+  run_on_init: true
+
+- name: run second command
+  run: \"echo '{{test}} command' | sed  s/test/second/g\"
+  change: \"$WORKDIR/**\"
+  run_on_init: true
+
+- name: run third command
+  run: \"echo '{{test}} command' | sed  s/test/third/g\"
+  change: \"$WORKDIR/**\"
+  run_on_init: true
+" > "$config_file"
+
+echo "target: $target";
+
+$TEST_DIR/funzzy --config="$config_file" \
+  --target="$target" > "$WORKDIR/output.txt" &
+FUNZZY_PID=$!
+
+wait_for_file "$WORKDIR/output.txt"
+assert_file_contains "$WORKDIR/output.txt" "{{second}} command"
+assert_file_not_contains "$WORKDIR/output.txt" "{{first}} command"
+assert_file_not_contains "$WORKDIR/output.txt" "{{third}} command"
+
+cleanup