ExCompileGraph.Dependency (ex_compile_graph v0.1.0)

Module contains API to answer queries based on the dependencies graph

recompile-dependencies

Recompile dependencies

Given two files A and B, we state that A has a recompile dependency to B iff when B recompiles, A must recompiles as well.

Recompile dependencies can be formed in these scenarios:

  1. A has a compile dependency to B
  2. A has a compile-then-runtime dependency to B (A has a compile dependency to A1 and A1 has a runtime dependency to B)
  3. A has a exports dependency to B
  4. A has a exports-then-compile dependency to B (A has a exports dependency to A1 and A1 has a compile dependency to B)

There are two types of recompile dependencies, definite and indefinite.

  • Definite dependencies mean if the target file recompiles, the source file will DEFINITELY recompile. Scenario 1 and 2 above fell into this type.
  • Indefinite dependencies mean if the target file recompiles, the source file MAY or MAY NOT recompile. This is because exports dependencies depend on modules API, namely structs and public functions. So when a target file recompiles, but its struct definitions and public functions don't change, the source file won't recompile. Scenario 3 and 4 above fell into this type.

Link to this section Summary

Functions

Given two files and their dependency type, return all the causes for such dependency

Given a sink file and a graph, find all source files which have a dependency_type on the sink file

Returns all files which have a recompile dependency to the target file

Given two files which have a recompile dependency, return a detailed explanation of why such dependency exists

Link to this section Types

Link to this type

dependency_causes_params()

@type dependency_causes_params() :: %{
  source_file: ExCompileGraph.file_path(),
  sink_file: ExCompileGraph.file_path(),
  manifest: binary(),
  dependency_type: ExCompileGraph.dependency_type()
}
Link to this type

dependency_path()

@type dependency_path() :: [{dependency_type(), ExCompileGraph.file_path()}]
Link to this type

dependency_type()

@type dependency_type() :: :compile | :exports | :runtime
Link to this type

recompile_dependency_causes_params()

@type recompile_dependency_causes_params() :: %{
  source_file: ExCompileGraph.file_path(),
  sink_file: ExCompileGraph.file_path(),
  manifest: binary(),
  reason: :compile | :exports_then_compile | :exports | :compile_then_runtime
}

Link to this section Functions

Link to this function

dependency_causes(params)

@spec dependency_causes(dependency_causes_params()) :: [
  ExCompileGraph.Dependency.Cause.t()
]

Given two files and their dependency type, return all the causes for such dependency

Note that this function only accepts direct dependencies

Link to this function

find_source_files(graph, sink_file, dependency_type, opts \\ [])

@spec find_source_files(:digraph.graph(), binary(), dependency_type(), [
  {:direct_only?, boolean()}
]) ::
  [{ExCompileGraph.file_path(), dependency_path()}]

Given a sink file and a graph, find all source files which have a dependency_type on the sink file

options

Options

  • direct_only?: whether to count only direct dependency or include transitive ones. Default: true
Link to this function

recompile_dependencies(graph, target_file)

@spec recompile_dependencies(:digraph.graph(), ExCompileGraph.file_path()) :: %{
  compile: [{ExCompileGraph.file_path(), dependency_path()}],
  exports_then_compile: [{ExCompileGraph.file_path(), dependency_path()}],
  exports: [{ExCompileGraph.file_path(), dependency_path()}],
  compile_then_runtime: [{ExCompileGraph.file_path(), dependency_path()}]
}

Returns all files which have a recompile dependency to the target file

Link to this function

recompile_dependency_causes(params)

Given two files which have a recompile dependency, return a detailed explanation of why such dependency exists

Imagine the relationship likes a chain of files with two tips are our two input files. We will resolves the causes for each link with dependency_causes/1