@@ -61,7 +61,8 @@ const (
6161)
6262
6363const sourceQuery = "kind('source file', deps(set(%s)))"
64- const buildQuery = "buildfiles(deps(set(%s)))"
64+ const targetQuery = "deps(set(%s))"
65+ const buildQuery = "buildfiles(set(%s))"
6566
6667type IBazel struct {
6768 debounceDuration time.Duration
@@ -311,8 +312,21 @@ func (i *IBazel) iteration(command string, commandToRun runnableCommand, targets
311312 case QUERY :
312313 // Query for which files to watch.
313314 log .Logf ("Querying for files to watch..." )
314- i .watchFiles (fmt .Sprintf (buildQuery , joinedTargets ), i .buildFileWatcher )
315- i .watchFiles (fmt .Sprintf (sourceQuery , joinedTargets ), i .sourceFileWatcher )
315+
316+ toWatchBuildFiles , err := i .queryForBuildFiles (joinedTargets )
317+ if err != nil {
318+ log .Errorf ("Error querying for build files: %v" , err )
319+ } else {
320+ i .watchFiles (toWatchBuildFiles , i .buildFileWatcher )
321+ }
322+
323+ toWatchSourceFiles , err := i .queryForSourceFiles (joinedTargets )
324+ if err != nil {
325+ log .Errorf ("Error querying for source files: %v" , err )
326+ } else {
327+ i .watchFiles (toWatchSourceFiles , i .sourceFileWatcher )
328+ }
329+
316330 i .state = RUN
317331 case DEBOUNCE_RUN :
318332 select {
@@ -492,63 +506,96 @@ func (i *IBazel) dumpRootRepoMapping() (map[string]string, *bytes.Buffer, error)
492506 return res , stderr , nil
493507}
494508
495- func (i * IBazel ) queryForSourceFiles (query string ) ([]string , error ) {
509+ func (i * IBazel ) queryForSourceFiles (targets string ) ([]string , error ) {
496510 b := i .newBazel ()
497511
498- localRepositories , err := i . realLocalRepositoryPaths ( )
512+ res , err := b . CQuery ( i . cQueryArgs ( fmt . Sprintf ( sourceQuery , targets )) ... )
499513 if err != nil {
514+ log .Errorf ("Bazel cquery failed: %v" , err )
500515 return nil , err
501516 }
502517
503- res , err := b .Query (i .queryArgs (query )... )
518+ labels := make ([]string , 0 , len (res .Results ))
519+ for _ , target := range res .Results {
520+ switch * target .Target .Type {
521+ case blaze_query .Target_SOURCE_FILE :
522+ label := target .Target .SourceFile .GetName ()
523+ labels = append (labels , label )
524+ default :
525+ log .Errorf ("%v\n " , target )
526+ }
527+ }
528+
529+ return i .labelsToWatch (labels )
530+ }
531+
532+ func (i * IBazel ) queryForBuildFiles (targets string ) ([]string , error ) {
533+ b := i .newBazel ()
534+
535+ targetRes , err := b .CQuery (i .cQueryArgs (fmt .Sprintf (targetQuery , targets ))... )
504536 if err != nil {
505- log .Errorf ("Bazel query failed: %v" , err )
537+ log .Errorf ("Bazel target query failed: %v" , err )
506538 return nil , err
507539 }
508540
509- workspacePath , err := i .workspaceFinder . FindWorkspace ()
541+ localRepositories , err := i .realLocalRepositoryPaths ()
510542 if err != nil {
511- log .Errorf ("Error finding workspace: %v" , err )
512543 return nil , err
513544 }
514-
515- toWatch := make ([]string , 0 , len (res .GetTarget ()))
516- for _ , target := range res .GetTarget () {
517- switch * target .Type {
518- case blaze_query .Target_SOURCE_FILE :
519- label := target .GetSourceFile ().GetName ()
545+ quotedBuildTargets := make ([]string , 0 , len (targetRes .Results ))
546+ for _ , configuredTarget := range targetRes .Results {
547+ target := configuredTarget .GetTarget ()
548+ if * target .Type == blaze_query .Target_RULE {
549+ label := target .GetRule ().GetName ()
520550 if strings .HasPrefix (label , "@" ) {
521- repo , target := parseTarget (label )
522- if realPath , ok := localRepositories [repo ]; ok {
523- label = strings .Replace (target , ":" , string (filepath .Separator ), 1 )
524- toWatch = append (toWatch , filepath .Join (realPath , label ))
525- break
551+ repo , _ := parseTarget (label )
552+ if _ , ok := localRepositories [repo ]; ! ok {
553+ continue
526554 }
527- continue
528555 }
529556 if strings .HasPrefix (label , "//external" ) {
530557 continue
531558 }
559+ // Build targets may contain characters that shells don't like.
560+ // Quote them to guarantee the correct behavior.
561+ quotedBuildTargets = append (quotedBuildTargets , fmt .Sprintf ("%q" , label ))
562+ }
563+ }
564+
565+ f , err := os .CreateTemp ("" , "query" )
566+ if err != nil {
567+ return nil , fmt .Errorf ("failed to create query file: %w" , err )
568+ }
569+ defer func () {
570+ f .Close ()
571+ os .Remove (f .Name ())
572+ }()
573+ _ , err = f .WriteString (fmt .Sprintf (buildQuery , strings .Join (quotedBuildTargets , " " )))
574+ if err != nil {
575+ return nil , fmt .Errorf ("failed to write query file: %w" , err )
576+ }
577+
578+ res , err := b .Query (i .queryArgs (fmt .Sprintf ("--query_file=%s" , f .Name ()))... )
579+ if err != nil {
580+ log .Errorf ("Bazel query failed: %v" , err )
581+ return nil , err
582+ }
532583
533- label = strings .Replace (strings .TrimPrefix (label , "//" ), ":" , string (filepath .Separator ), 1 )
534- toWatch = append (toWatch , filepath .Join (workspacePath , label ))
535- break
584+ labels := make ([]string , 0 , len (res .GetTarget ()))
585+ for _ , target := range res .GetTarget () {
586+ switch * target .Type {
587+ case blaze_query .Target_SOURCE_FILE :
588+ label := target .GetSourceFile ().GetName ()
589+ labels = append (labels , label )
536590 default :
537591 log .Errorf ("%v\n " , target )
538592 }
539593 }
540594
541- return toWatch , nil
595+ return i . labelsToWatch ( labels )
542596}
543597
544- func (i * IBazel ) watchFiles (query string , watcher common.Watcher ) {
545- toWatch , err := i .queryForSourceFiles (query )
546- if err != nil {
547- // If the query fails, just keep watching the same files as before
548- log .Errorf ("Error querying for source files: %v" , err )
549- return
550- }
551-
598+ func (i * IBazel ) watchFiles (toWatch []string , watcher common.Watcher ) {
552599 filesWatched := map [string ]struct {}{}
553600 uniqueDirectories := map [string ]struct {}{}
554601
@@ -569,18 +616,52 @@ func (i *IBazel) watchFiles(query string, watcher common.Watcher) {
569616 }
570617
571618 watchList := keys (uniqueDirectories )
572- err = watcher .UpdateAll (watchList )
619+ err : = watcher .UpdateAll (watchList )
573620 if err != nil {
574621 log .Errorf ("Error(s) updating watch list:\n %v" , err )
575622 }
576623
577624 if len (filesWatched ) == 0 {
578- log .Errorf ("Didn't find any files to watch from query %s" , query )
625+ log .Errorf ("Didn't find any files to watch for" )
579626 }
580627
581628 i .filesWatched [watcher ] = filesWatched
582629}
583630
631+ func (i * IBazel ) labelsToWatch (labels []string ) ([]string , error ) {
632+ localRepositories , err := i .realLocalRepositoryPaths ()
633+ if err != nil {
634+ return nil , err
635+ }
636+
637+ workspacePath , err := i .workspaceFinder .FindWorkspace ()
638+ if err != nil {
639+ log .Errorf ("Error finding workspace: %v" , err )
640+ return nil , err
641+ }
642+
643+ toWatch := make ([]string , 0 , len (labels ))
644+ for _ , label := range labels {
645+ if strings .HasPrefix (label , "@" ) {
646+ repo , target := parseTarget (label )
647+ if realPath , ok := localRepositories [repo ]; ok {
648+ label = strings .Replace (target , ":" , string (filepath .Separator ), 1 )
649+ toWatch = append (toWatch , filepath .Join (realPath , label ))
650+ break
651+ }
652+ continue
653+ }
654+ if strings .HasPrefix (label , "//external" ) {
655+ continue
656+ }
657+
658+ label = strings .Replace (strings .TrimPrefix (label , "//" ), ":" , string (filepath .Separator ), 1 )
659+ toWatch = append (toWatch , filepath .Join (workspacePath , label ))
660+ }
661+
662+ return toWatch , nil
663+ }
664+
584665func (i * IBazel ) queryArgs (args ... string ) []string {
585666 queryArgs := append ([]string (nil ), args ... )
586667
0 commit comments