void Tool::ScriptResolver:: resolve( Tool::Context *toolContext, pbxsetting::Environment const &environment, Phase::File const &input) const { Target::BuildRules::BuildRule::shared_ptr const &buildRule = input.buildRule(); if (buildRule == nullptr || buildRule->script().empty()) { fprintf(stderr, "warning: invalid or missing build rule for script\n"); return; } std::string inputAbsolutePath = FSUtil::ResolveRelativePath(input.path(), toolContext->workingDirectory()); std::string inputRelativePath = FSUtil::GetRelativePath(inputAbsolutePath, toolContext->workingDirectory()); pbxsetting::Value logMessage = pbxsetting::Value::Parse("RuleScriptExecution " + inputRelativePath + " $(variant) $(arch)"); /* * Add the public input file build settings. These can be used within the * script or inside the list of output paths. */ pbxsetting::Level level = pbxsetting::Level({ pbxsetting::Setting::Create("INPUT_FILE_PATH", inputAbsolutePath), pbxsetting::Setting::Parse("INPUT_FILE_DIR", "$(INPUT_FILE_PATH:dir)"), pbxsetting::Setting::Parse("INPUT_FILE_NAME", "$(INPUT_FILE_PATH:file)"), pbxsetting::Setting::Parse("INPUT_FILE_BASE", "$(INPUT_FILE_PATH:base)"), pbxsetting::Setting::Parse("INPUT_FILE_SUFFIX", "$(INPUT_FILE_PATH:suffix)"), pbxsetting::Setting::Create("INPUT_FILE_REGION_PATH_COMPONENT", input.localization()), // TODO(grp): Verify format of this. }); pbxsetting::Environment ruleEnvironment = environment; ruleEnvironment.insertFront(level, false); /* * Only resolve the output paths once the input paths settings are in the * environment. The output paths can use the input path settings. */ std::vector<std::string> outputFiles; std::transform(buildRule->outputFiles().begin(), buildRule->outputFiles().end(), std::back_inserter(outputFiles), [&](pbxsetting::Value const &output) -> std::string { std::string path = ruleEnvironment.expand(output); return FSUtil::ResolveRelativePath(path, toolContext->workingDirectory()); }); /* * Compute the final environment by adding the standard script levels. */ ruleEnvironment.insertFront(ScriptInputOutputLevel({ inputAbsolutePath }, outputFiles, false), false); std::unordered_map<std::string, std::string> environmentVariables = ruleEnvironment.computeValues(pbxsetting::Condition::Empty()); Tool::Invocation invocation; invocation.executable() = Tool::Invocation::Executable::Absolute("/bin/sh"); invocation.arguments() = { "-c", buildRule->script() }; invocation.environment() = environmentVariables; invocation.workingDirectory() = toolContext->workingDirectory(); invocation.inputs() = { inputAbsolutePath }; invocation.outputs() = outputFiles; invocation.logMessage() = ruleEnvironment.expand(logMessage); invocation.showEnvironmentInLog() = true; toolContext->invocations().push_back(invocation); }
void Tool::ScriptResolver:: resolve( Tool::Context *toolContext, pbxsetting::Environment const &environment, pbxproj::PBX::ShellScriptBuildPhase::shared_ptr const &buildPhase) const { pbxsetting::Level level = pbxsetting::Level({ pbxsetting::Setting::Create("BuildPhaseName", (!buildPhase->name().empty() ? buildPhase->name() : "Run Script")), pbxsetting::Setting::Create("BuildPhaseIdentifier", buildPhase->blueprintIdentifier()), }); pbxsetting::Environment phaseEnvironment = environment; phaseEnvironment.insertFront(level, false); pbxsetting::Value scriptPath = pbxsetting::Value::Parse("$(TEMP_FILES_DIR)/Script-$(BuildPhaseIdentifier).sh"); pbxsetting::Value logMessage = pbxsetting::Value::Parse("PhaseScriptExecution $(BuildPhaseName:quote) ") + scriptPath; std::vector<std::string> inputFiles; std::transform(buildPhase->inputPaths().begin(), buildPhase->inputPaths().end(), std::back_inserter(inputFiles), [&](pbxsetting::Value const &input) -> std::string { std::string path = environment.expand(input); return FSUtil::ResolveRelativePath(path, toolContext->workingDirectory()); }); std::vector<std::string> outputFiles; std::transform(buildPhase->outputPaths().begin(), buildPhase->outputPaths().end(), std::back_inserter(outputFiles), [&](pbxsetting::Value const &output) -> std::string { std::string path = environment.expand(output); return FSUtil::ResolveRelativePath(path, toolContext->workingDirectory()); }); std::string scriptFilePath = phaseEnvironment.expand(scriptPath); std::string contents = (!buildPhase->shellPath().empty() ? "#!" + buildPhase->shellPath() + "\n" : "") + buildPhase->shellScript(); Tool::Invocation::AuxiliaryFile scriptFile = Tool::Invocation::AuxiliaryFile(scriptFilePath, contents, true); pbxsetting::Environment scriptEnvironment = environment; scriptEnvironment.insertFront(ScriptInputOutputLevel(inputFiles, outputFiles, true), false); std::unordered_map<std::string, std::string> environmentVariables = scriptEnvironment.computeValues(pbxsetting::Condition::Empty()); Tool::Invocation invocation; invocation.executable() = Tool::Invocation::Executable::Absolute("/bin/sh"); invocation.arguments() = { "-c", Escape::Shell(scriptFilePath) }; invocation.environment() = environmentVariables; invocation.workingDirectory() = toolContext->workingDirectory(); invocation.phonyInputs() = inputFiles; /* User-specified, may not exist. */ invocation.outputs() = outputFiles; invocation.auxiliaryFiles() = { scriptFile }; invocation.logMessage() = phaseEnvironment.expand(logMessage); invocation.showEnvironmentInLog() = buildPhase->showEnvVarsInLog(); toolContext->invocations().push_back(invocation); }