Skip to content

tinywasm/depfind

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

21 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

godepfind

Project Badges

A Go library for finding reverse dependencies and determining which main packages are affected by file changes.

Overview

godepfind helps you identify which packages import your target packages (reverse dependency analysis) and, more importantly, which main packages need to be recompiled when you modify a specific Go file.

This is particularly useful for:

  • Build systems that need to know which applications to rebuild when files change
  • Development tools that optimize compilation by only rebuilding affected main packages
  • CI/CD pipelines that want to minimize build time by targeting only affected applications

Installation

go get github.com/tinywasm/depfind

Features

1. Cached Dependency Analysis

NEW: Intelligent caching system for performance in development environments where files change regularly.

2. Handler-Based File Ownership

NEW: Determine which handler should process a file change using smart dependency analysis.

3. Find Reverse Dependencies

Find which packages import specified target packages.

4. File-to-Main Mapping

Main feature: Given a modified file name, find which main packages depend on it (directly or transitively).

Usage

Basic Setup

import "github.com/tinywasm/depfind"

// Create a new finder instance for your project
finder := godepfind.New("/path/to/your/go/project")

// Optional: Include test imports in dependency analysis
finder.SetTestImports(true)

Find Which Main Packages Use a File

Primary use case: When you modify a file, find which main packages need recompilation.

// After modifying "database.go", find affected main packages
mains, err := finder.GoFileComesFromMain("database.go")
if err != nil {
    log.Fatal(err)
}

fmt.Printf("Main packages affected by database.go changes: %v\n", mains)
// Output: [myproject/cmd/server myproject/cmd/cli]

File Ownership (NEW)

For development tools: Determine which handler should process a file change.

// Check if a file change belongs to this handler
mainInputFileRelativePath := "app/server/main.go"
isMine, err := finder.ThisFileIsMine(mainInputFileRelativePath, "./internal/db/database.go", "write")
if err != nil {
    log.Fatal(err)
}

if isMine {
    fmt.Println("This handler should process the file change")
    // Process the file change...
}

Find Reverse Dependencies

// Find packages that import "fmt" or "os"
deps, err := finder.FindReverseDeps("./...", []string{"fmt", "os"})
if err != nil {
    log.Fatal(err)
}

fmt.Printf("Packages importing fmt or os: %v\n", deps)

Real-World Example

Imagine you have a Go project with multiple applications:

myproject/
├── go.mod
├── cmd/
│   ├── server/main.go      (web server)
│   ├── cli/main.go         (command line tool)  
│   └── worker/main.go      (background worker)
├── internal/
│   ├── database/db.go      (shared database package)
│   ├── auth/auth.go        (authentication)
│   └── utils/helpers.go    (utilities)

Scenario: You modify internal/database/db.go

finder := godepfind.New("/path/to/myproject")

// Traditional approach: Find which main packages are affected
affected, err := finder.GoFileComesFromMain("db.go")
if err != nil {
    log.Fatal(err)
}

fmt.Printf("Need to rebuild: %v\n", affected)
// Output: [myproject/cmd/server myproject/cmd/worker]
// Note: cmd/cli is NOT affected because it doesn't import the database package

// NEW: Handler-based approach for development tools
// Check if server handler should process this change
mainInputFileRelativePath := "cmd/server/main.go"
shouldProcess, err := finder.ThisFileIsMine(mainInputFileRelativePath, "./internal/database/db.go", "write")
if err != nil {
    log.Fatal(err)
}

if shouldProcess {
    fmt.Println("Server handler will process this database change")
    // Automatically compile server, restart, etc.
}

Now your build system knows to only recompile the server and worker applications, not the cli tool.

API Reference

Core Functions

New(rootDir string) *GoDepFind

Creates a new GoDepFind instance with intelligent caching.

  • rootDir: Path to the Go module root directory (where go.mod is located)

SetTestImports(enabled bool)

Enable/disable inclusion of test imports in dependency analysis.

GoFileComesFromMain(fileName string) ([]string, error)

Main function: Find which main packages depend on the given file.

  • fileName: Name of the file (e.g., "database.go", "helpers.go")
  • Returns: Slice of main package paths that depend on this file

FindReverseDeps(sourcePath string, targetPaths []string) ([]string, error)

Find packages in sourcePath that import any of the targetPaths.

  • sourcePath: Path pattern to search (e.g., "./...", "./cmd/...")
  • targetPaths: Packages to find dependencies for
  • Returns: Slice of packages that import the targets

New Cache-Enabled Functions

ThisFileIsMine(mainInputFileRelativePath, filePath, event string) (bool, error)

NEW: Determine if a file change belongs to a specific handler using intelligent dependency analysis.

  • mainInputFileRelativePath: Path to the main file that this handler is responsible for managing.
  • filePath: Full path to the changed file (e.g., "./internal/db/database.go") - filePath must include directory separators
  • event: Type of change ("write", "create", "remove", "rename")
  • Returns: (true if handler should process, error if any)

Important: filePath must be a complete path with directory separators (e.g., "./internal/db/database.go"). Simple filenames like "database.go" are not allowed and will return an error.

API Requirements & Validation

File Path Requirements

The ThisFileIsMine function has strict validation requirements for the filePath parameter:

✅ Valid Paths:

  • "./internal/db/database.go" - Relative path with directory
  • "app/web/main.go" - Relative path with subdirectory
  • "/absolute/path/main.go" - Absolute path
  • "pwa/main.server.go" - Path with filename containing dots

❌ Invalid Paths:

  • "" - Empty string
  • "database.go" - Filename only (no directory separators)
  • "file.go" - Filename only (no directory separators)

Validation Rules:

  • filePath cannot be empty
  • filePath must contain at least one directory separator (/ or \)
  • Simple filenames without directory paths will return an error

This validation ensures deterministic file ownership by preventing ambiguity between files with the same name in different directories.

Performance & Caching

godepfind now includes an intelligent caching system that dramatically improves performance in development environments:

📊 Benchmark Summary

Scenario Without Cache With Cache Speedup
GoFileComesFromMain ~14,000,000 ns/op ~194 ns/op ~72,000x
ThisFileIsMine ~13,000,000 ns/op ~22,000 ns/op ~590x
Real-World Scenario ~8,500,000 ns/op ~310 ns/op* ~27,000x*
Multiple Files ~55,000,000 ns/op ~860 ns/op ~64,000x
Cache Invalidation N/A ~305 ns/op -

See docs/BENCHMARK.md for full results and details.

Note: Real-World Scenario with cache is extremely fast; actual value is similar to other cached operations.

Expert Note: GoDepFind's cache system achieves real-time performance (from ~14,000,000 ns/op to ~194 ns/op, ~72,000x faster) and reduces memory allocations to nearly zero in repeated queries. This makes it highly suitable for modern development environments, file watchers, and incremental build systems.

  • Lazy Loading: Cache is built only when needed
  • Selective Invalidation: Only affected packages are re-analyzed when files change
  • Memory Efficient: Cache is stored in memory and cleaned up automatically
  • Event-Driven: Cache updates automatically based on file change events

This makes godepfind suitable for real-time file watching in development tools.

Use Cases

  1. Smart Build Systems: Only rebuild applications affected by code changes with automatic cache management
  2. Development Tools: IDE extensions that show which apps are affected by current changes
  3. File Watchers: Real-time development environments that respond to file changes intelligently
  4. CI/CD Optimization: Reduce build time by targeting only affected main packages
  5. Dependency Analysis: Understand how your modules are interconnected
  6. Refactoring Safety: Know the blast radius of changes before making them

Requirements

  • Go 1.19+
  • Valid Go module (go.mod file)
  • Project must be buildable with go list ./...

Acknowledgments

This library is based on the excellent work of Andrew Wilkins and his rdep tool. The core reverse dependency detection logic was adapted and extended from his implementation to provide file-to-main package mapping functionality.

Special thanks to Andrew for creating the foundational reverse dependency analysis that made this library possible.

About

A Go tool to find reverse dependencies - lists packages that import specified target packages

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Contributors 2

  •  
  •