in codegen/module.go [1194:1344]
func (system *ModuleSystem) IncrementalBuild(
packageRoot,
baseDirectory,
targetGenDir string,
instances []ModuleDependency,
resolvedModules map[string][]*ModuleInstance,
options Options,
) (map[string][]*ModuleInstance, error) {
skipModuleMap := map[*ModuleInstance]struct{}{}
toBeBuiltModules := make(map[string][]*ModuleInstance)
for _, className := range system.classOrder {
var wg sync.WaitGroup
wg.Add(len(resolvedModules[className]))
ch := make(chan *populateSpecRes, len(resolvedModules[className]))
for _, instance := range resolvedModules[className] {
go func(instance *ModuleInstance) {
defer wg.Done()
if err := system.populateSpec(instance); err != nil {
baseErr := errors.Cause(err)
if _, ok := baseErr.(*IgnorePopulateSpecStageErr); ok {
return
}
if _, ok := baseErr.(*ErrorSkipCodeGen); ok {
// HACK: to get get of bad modules, which should not be even be loaded in dag at first place
ch <- &populateSpecRes{mi: instance}
} else {
ch <- &populateSpecRes{err: err}
}
}
}(instance)
}
go func() {
wg.Wait()
close(ch)
}()
for psRes := range ch {
if psRes.err != nil {
return nil, psRes.err
}
skipModuleMap[psRes.mi] = struct{}{}
}
}
resolvedModulesCopy := map[string][]*ModuleInstance{}
for cls, modules := range resolvedModules {
for _, m := range modules {
if _, ok := skipModuleMap[m]; ok {
// skipping error modules
fmt.Println("skipping module gen", m.InstanceName)
continue
}
m.RecursiveDependencies = trimSkipDependencies(m.RecursiveDependencies, skipModuleMap)
m.ResolvedDependencies = trimSkipDependencies(m.ResolvedDependencies, skipModuleMap)
resolvedModulesCopy[cls] = append(resolvedModulesCopy[cls], m)
}
}
resolvedModules = resolvedModulesCopy
if instances == nil || len(instances) == 0 {
for _, modules := range resolvedModules {
for _, instance := range modules {
instances = append(instances, instance.AsModuleDependency())
}
}
}
// If toBeBuiltModules is not empty already, it is likely that one of the modules does not implement
// the SpecProvider interface, hence incremental build is not possible.
if len(toBeBuiltModules) == 0 {
var err error
toBeBuiltModules, err = system.collectTransitiveDependencies(instances,
resolvedModules)
if err != nil {
// if incrementalBuild fails, perform a full build.
fmt.Printf("Falling back to full build due to err: %s\n", err.Error())
toBeBuiltModules = resolvedModules
}
}
moduleCount := 0
var moduleIndex int32
for _, moduleList := range toBeBuiltModules {
moduleCount += len(moduleList)
}
qpsLevels, err := PopulateQPSLevels(baseDirectory+"/endpoints", options.QPSLevelsEnabled)
if err != nil {
return nil, errors.Errorf(
"error in populating qps levels for base directory %q",
baseDirectory,
)
}
for _, class := range system.classOrder {
var wg sync.WaitGroup
wg.Add(len(toBeBuiltModules[class]))
ch := make(chan error, len(toBeBuiltModules[class]))
for _, moduleInstance := range toBeBuiltModules[class] {
go func(moduleInstance *ModuleInstance) {
defer wg.Done()
physicalGenDir := filepath.Join(targetGenDir, moduleInstance.Directory)
prettyDir, _ := filepath.Rel(baseDirectory, physicalGenDir)
PrintGenLine(moduleInstance.ClassType, moduleInstance.ClassName, moduleInstance.InstanceName,
prettyDir, int(atomic.AddInt32(&moduleIndex, 1)), moduleCount)
moduleInstance.QPSLevels = qpsLevels
if err := system.Build(packageRoot, baseDirectory, physicalGenDir, moduleInstance, options); err != nil {
ch <- err
}
}(moduleInstance)
}
go func() {
wg.Wait()
close(ch)
}()
for err := range ch {
if err != nil {
return nil, err
}
}
}
var wg sync.WaitGroup
ch := make(chan error, len(system.postGenHook))
for i, hook := range system.postGenHook {
if hook != nil {
wg.Add(1)
go func(hook PostGenHook) {
defer wg.Done()
if err := hook(toBeBuiltModules); err != nil {
ch <- errors.Wrapf(err, "error running %dth post generation hook", i)
}
}(hook)
}
}
go func() {
wg.Wait()
close(ch)
}()
for err := range ch {
if err != nil {
return toBeBuiltModules, err
}
}
return toBeBuiltModules, nil
}