std::unique_ptr BuildSystemEngineDelegate::lookupRule()

in lib/BuildSystem/BuildSystem.cpp [1504:1813]


std::unique_ptr<Rule> BuildSystemEngineDelegate::lookupRule(const KeyType& keyData) {
  // Decode the key.
  auto key = BuildKey::fromData(keyData);

  switch (key.getKind()) {
  case BuildKey::Kind::Unknown:
    break;
    
  case BuildKey::Kind::Command: {
    // Find the comand.
    auto it = getBuildDescription().getCommands().find(key.getCommandName());
    if (it == getBuildDescription().getCommands().end()) {
      // If there is no such command, produce an error task.
      return std::unique_ptr<Rule>(new BuildSystemRule(
        keyData,
        /*signature=*/{},
        /*Action=*/ [](BuildEngine& engine) -> Task* {
          return new MissingCommandTask();
        },
        /*IsValid=*/ [](BuildEngine&, const Rule&, const ValueType&) -> bool {
          // The cached result for a missing command is never valid.
          return false;
        }
      ));
    }

    // Create the rule for the command.
    Command* command = it->second.get();
    return std::unique_ptr<Rule>(new BuildSystemRule(
      keyData,
      command->getSignature(),
      /*Action=*/ [command](BuildEngine& engine) -> Task* {
        return new CommandTask(*command);
      },
      /*IsValid=*/ [command](BuildEngine& engine, const Rule& rule,
                             const ValueType& value) -> bool {
        return CommandTask::isResultValid(
            engine, *command, BuildValue::fromData(value));
      },
      /*UpdateStatus=*/ [command](BuildEngine& engine,
                                  core::Rule::StatusKind status) {
        return ::getBuildSystem(engine).getDelegate().commandStatusChanged(
            command, convertStatusKind(status));
      }
    ));
  }

  case BuildKey::Kind::CustomTask: {
    // Search for a tool which knows how to create the given custom task.
    //
    // FIXME: We should most likely have some kind of registration process so we
    // can do an efficient query here, but exactly how this should look isn't
    // clear yet.
    for (const auto& it: getBuildDescription().getTools()) {
      auto result = it.second->createCustomCommand(key);
      if (!result) continue;

      // Save the custom command.
      customTasks.emplace_back(std::move(result));
      Command *command = customTasks.back().get();
      
      return std::unique_ptr<Rule>(new BuildSystemRule(
        keyData,
        command->getSignature(),
        /*Action=*/ [command](BuildEngine& engine) -> Task* {
          return new CommandTask(*command);
        },
        /*IsValid=*/ [command](BuildEngine& engine, const Rule& rule,
                               const ValueType& value) -> bool {
          return CommandTask::isResultValid(
              engine, *command, BuildValue::fromData(value));
        },
        /*UpdateStatus=*/ [command](BuildEngine& engine,
                                    core::Rule::StatusKind status) {
          return ::getBuildSystem(engine).getDelegate().commandStatusChanged(
              command, convertStatusKind(status));
        }
      ));
    }
    
    // We were unable to create an appropriate custom command, produce an error
    // task.
    return std::unique_ptr<Rule>(new BuildSystemRule(
      keyData,
      /*signature=*/{},
      /*Action=*/ [](BuildEngine& engine) -> Task* {
        return new MissingCommandTask();
      },
      /*IsValid=*/ [](BuildEngine&, const Rule&, const ValueType&) -> bool {
        // The cached result for a missing command is never valid.
        return false;
      }
    ));
  }

  case BuildKey::Kind::DirectoryContents: {
    std::string path = key.getDirectoryPath();
    return std::unique_ptr<Rule>(new BuildSystemRule(
      keyData,
      /*signature=*/{},
      /*Action=*/ [path](BuildEngine& engine) -> Task* {
        return new DirectoryContentsTask(path);
      },
      /*IsValid=*/ [path](BuildEngine& engine, const Rule& rule,
          const ValueType& value) mutable -> bool {
        return DirectoryContentsTask::isResultValid(
            engine, path, BuildValue::fromData(value));
      }
    ));
  }

  case BuildKey::Kind::FilteredDirectoryContents: {
    std::string path = key.getFilteredDirectoryPath();
    std::string patterns = key.getContentExclusionPatterns();
    return std::unique_ptr<Rule>(new BuildSystemRule(
      keyData,
      /*signature=*/{},
      /*Action=*/ [path, patterns](BuildEngine& engine) -> Task* {
        BinaryDecoder decoder(patterns);
        return new FilteredDirectoryContentsTask(path, StringList(decoder));
      },
      /*IsValid=*/ nullptr
    ));
  }

  case BuildKey::Kind::DirectoryTreeSignature: {
    std::string path = key.getDirectoryTreeSignaturePath();
    std::string filters = key.getContentExclusionPatterns();
    return std::unique_ptr<Rule>(new BuildSystemRule(
      keyData,
      /*signature=*/{},
      /*Action=*/ [path, filters](
          BuildEngine& engine) mutable -> Task* {
        BinaryDecoder decoder(filters);
        return new DirectoryTreeSignatureTask(path, StringList(decoder));
      },
        // Directory signatures don't require any validation outside of their
        // concrete dependencies.
      /*IsValid=*/ nullptr
    ));
  }

  case BuildKey::Kind::DirectoryTreeStructureSignature: {
    std::string path = key.getDirectoryPath();
    return std::unique_ptr<Rule>(new BuildSystemRule(
      keyData,
      /*signature=*/{},
      /*Action=*/ [path](
          BuildEngine& engine) mutable -> Task* {
        return new DirectoryTreeStructureSignatureTask(path);
      },
        // Directory signatures don't require any validation outside of their
        // concrete dependencies.
      /*IsValid=*/ nullptr
    ));
  }
    
  case BuildKey::Kind::Node: {
    // Find the node.
    auto it = getBuildDescription().getNodes().find(key.getNodeName());
    BuildNode* node;
    if (it != getBuildDescription().getNodes().end()) {
      node = static_cast<BuildNode*>(it->second.get());
    } else {
      auto it = dynamicNodes.find(key.getNodeName());
      if (it != dynamicNodes.end()) {
        node = it->second.get();
      } else {
        // Create nodes on the fly for any unknown ones.
        auto nodeOwner = system.lookupNode(
            key.getNodeName(), /*isImplicit=*/true);
        node = nodeOwner.get();
        dynamicNodes[key.getNodeName()] = std::move(nodeOwner);
      }
    }

    // Create the rule used to construct this node.
    //
    // We could bypass this level and directly return the rule to run the
    // command, which would reduce the number of tasks in the system. For now we
    // do the uniform thing, but do differentiate between input and command
    // nodes.

    // Create an input node if there are no producers.
    if (node->getProducers().empty()) {
      if (node->isVirtual()) {
        return std::unique_ptr<Rule>(new BuildSystemRule(
          keyData,
          node->getSignature(),
          /*Action=*/ [](BuildEngine& engine) -> Task* {
            return new VirtualInputNodeTask();
          },
          /*IsValid=*/ [node](BuildEngine& engine, const Rule& rule,
                                const ValueType& value) -> bool {
            return VirtualInputNodeTask::isResultValid(
                engine, *node, BuildValue::fromData(value));
          }
        ));
      }

      if (node->isDirectory()) {
        return std::unique_ptr<Rule>(new BuildSystemRule(
          keyData,
          node->getSignature(),
          /*Action=*/ [node](BuildEngine& engine) -> Task* {
            return new DirectoryInputNodeTask(*node);
          },
            // Directory nodes don't require any validation outside of their
            // concrete dependencies.
          /*IsValid=*/ nullptr
        ));
      }

      if (node->isDirectoryStructure()) {
        return std::unique_ptr<Rule>(new BuildSystemRule(
          keyData,
          node->getSignature(),
          /*Action=*/ [node](BuildEngine& engine) -> Task* {
            return new DirectoryStructureInputNodeTask(*node);
          },
            // Directory nodes don't require any validation outside of their
            // concrete dependencies.
          /*IsValid=*/ nullptr
        ));
      }
      
      return std::unique_ptr<Rule>(new BuildSystemRule(
        keyData,
        node->getSignature(),
        /*Action=*/ [node](BuildEngine& engine) -> Task* {
          return new FileInputNodeTask(*node);
        },
        /*IsValid=*/ [node](BuildEngine& engine, const Rule& rule,
                            const ValueType& value) -> bool {
          return FileInputNodeTask::isResultValid(
              engine, *node, BuildValue::fromData(value));
        }
      ));
    }

    // Otherwise, create a task for a produced node.
    return std::unique_ptr<Rule>(new BuildSystemRule(
      keyData,
      node->getSignature(),
      /*Action=*/ [node](BuildEngine& engine) -> Task* {
        return new ProducedNodeTask(*node);
      },
      /*IsValid=*/ [node](BuildEngine& engine, const Rule& rule,
                          const ValueType& value) -> bool {
        return ProducedNodeTask::isResultValid(
            engine, *node, BuildValue::fromData(value));
      }
    ));
  }

  case BuildKey::Kind::Stat: {
    StatNode* statnode;
    auto it = dynamicStatNodes.find(key.getStatName());
    if (it != dynamicStatNodes.end()) {
      statnode = it->second.get();
    } else {
      // Create nodes on the fly for any unknown ones.
      auto statOwner = llvm::make_unique<StatNode>(key.getStatName());
      statnode = statOwner.get();
      dynamicStatNodes[key.getStatName()] = std::move(statOwner);
    }

    // Create the rule to construct this target.
    return std::unique_ptr<Rule>(new BuildSystemRule(
      keyData,
      /*signature=*/{},
      /*Action=*/ [statnode](BuildEngine& engine) -> Task* {
        return new StatTask(*statnode);
      },
      /*IsValid=*/ [statnode](BuildEngine& engine, const Rule& rule,
                            const ValueType& value) -> bool {
        return StatTask::isResultValid(
            engine, *statnode, BuildValue::fromData(value));
      }
    ));
  }
  case BuildKey::Kind::Target: {
    // Find the target.
    auto it = getBuildDescription().getTargets().find(key.getTargetName());
    if (it == getBuildDescription().getTargets().end()) {
      // FIXME: Invalid target name, produce an error.
      assert(0 && "FIXME: invalid target");
      abort();
    }

    // Create the rule to construct this target.
    Target* target = it->second.get();
    return std::unique_ptr<Rule>(new BuildSystemRule(
      keyData,
      /*signature=*/{},
      /*Action=*/ [target](BuildEngine& engine) -> Task* {
        return new TargetTask(*target);
      },
      /*IsValid=*/ [target](BuildEngine& engine, const Rule& rule,
                            const ValueType& value) -> bool {
        return TargetTask::isResultValid(
            engine, *target, BuildValue::fromData(value));
      }
    ));
  }
  }

  assert(0 && "invalid key type");
  abort();
}