func watchTask(root string, logName string, handler func(e *watcher.FileEvent)) { bufferSize := 2048 watchr, err := watcher.NewWatcher(bufferSize) if err != nil { util.Panic("project", "%v\n", err) } watchr.WatchRecursive(root) watchr.ErrorHandler = func(err error) { util.Error("project", "%v\n", err) } // this function will block forever, Ctrl+C to quit app var lastHappenedTime int64 firstTime := true for { if firstTime { util.Info(logName, "watching %s ...\n", root) firstTime = false } event := <-watchr.Event //util.Debug("DBG", "watchr.Event %+v\n", event) isOlder := event.UnixNano < lastHappenedTime lastHappenedTime = event.UnixNano if isOlder { continue } handler(event) } }
func (project *Project) mustTask(name string) (*Project, *Task) { namespace, taskName := project.namespaceTaskName(name) proj := project.Namespace[namespace] if proj == nil { util.Panic("project", "Could not find project having namespace \"%s\"\n", namespace) } task := proj.Tasks[taskName] if task == nil { util.Error("ERR", `"%s" task is not defined`+"\n", name) os.Exit(1) } return proj, task }
// Task adds a task to the project. func (project *Project) Task(name string, args ...interface{}) *Task { runOnce := false if strings.HasSuffix(name, "?") { runOnce = true name = str.ChompRight(name, "?") } task := &Task{Name: name, RunOnce: runOnce} for _, t := range args { switch t := t.(type) { default: util.Panic("project", "unexpected type %T\n", t) // %T prints whatever type t has case Watch: task.Watch(t...) printDeprecatedWatchWarning(name, t) case W: task.Watch(t...) printDeprecatedWatchWarning(name, t) case Dependencies: task.Dependencies = t case D: task.Dependencies = t case Debounce: task.Debounce(int64(t)) printDeprecatedDebounceWarning(name, int64(t)) case func(): task.Handler = VoidHandlerFunc(t) case func() error: task.Handler = HandlerFunc(t) case func(*Context): task.Handler = VoidContextHandlerFunc(t) case func(*Context) error: task.Handler = ContextHandlerFunc(t) case string: task.Description(t) printDeprecatedDescriptionWarning(name, t) } } project.Tasks[name] = task return task }
// Glob returns files and dirctories that match patterns. Patterns must use // slashes, even Windows. // // Special chars. // // /**/ - match zero or more directories // {a,b} - match a or b, no spaces // * - match any non-separator char // ? - match a single non-separator char // **/ - match any directory, start of pattern only // /** - match any this directory, end of pattern only // ! - removes files from resultset, start of pattern only // func Glob(patterns []string) ([]*FileAsset, []*RegexpInfo, error) { // TODO very inefficient and unintelligent, optimize later m := map[string]*FileAsset{} regexps := []*RegexpInfo{} for _, pattern := range patterns { remove := strings.HasPrefix(pattern, "!") if remove { pattern = pattern[1:] if hasMeta(pattern) { re := Globexp(pattern) regexps = append(regexps, &RegexpInfo{Regexp: re, Negate: true}) for path := range m { if re.MatchString(path) { m[path] = nil } } } else { path := gpath.Clean(pattern) m[path] = nil } } else { if hasMeta(pattern) { re := Globexp(pattern) regexps = append(regexps, &RegexpInfo{Regexp: re}) root := patternRoot(pattern) if root == "" { util.Panic("glob", "Cannot get root from pattern: %s", pattern) } fileAssets, err := walkFiles(root) if err != nil { return nil, nil, err } for _, file := range fileAssets { if re.MatchString(file.Path) { // TODO closure problem assigning &file tmp := file m[file.Path] = tmp } } } else { path := gpath.Clean(pattern) info, err := os.Stat(path) if err != nil { return nil, nil, err } fa := &FileAsset{Path: path, FileInfo: info} m[path] = fa } } } //log.Printf("m %v", m) keys := []*FileAsset{} for _, it := range m { if it != nil { keys = append(keys, it) } } return keys, regexps, nil }