mirror of
https://github.com/github/codeql.git
synced 2026-04-29 02:35:15 +02:00
Swift: surface error about unsupported SPM build
This commit is contained in:
@@ -9,36 +9,23 @@
|
||||
|
||||
#include "swift/xcode-autobuilder/XcodeWorkspaceParser.h"
|
||||
#include "swift/xcode-autobuilder/CFHelpers.h"
|
||||
#include "swift/logging/SwiftLogging.h"
|
||||
#include "swift/xcode-autobuilder/CustomizingBuildDiagnostics.h"
|
||||
|
||||
namespace codeql_diagnostics {
|
||||
constexpr codeql::SwiftDiagnosticsSource no_project_found{
|
||||
"no_project_found", "No Xcode project or workspace detected", customizingBuildAction,
|
||||
customizingBuildHelpLinks};
|
||||
} // namespace codeql_diagnostics
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
static codeql::Logger& logger() {
|
||||
static codeql::Logger ret{"project"};
|
||||
return ret;
|
||||
}
|
||||
|
||||
struct TargetData {
|
||||
std::string workspace;
|
||||
std::string project;
|
||||
std::string type;
|
||||
};
|
||||
|
||||
typedef std::unordered_map<std::string, CFDictionaryRef> Targets;
|
||||
typedef std::unordered_map<std::string, std::vector<std::string>> Dependencies;
|
||||
typedef std::unordered_map<std::string, std::vector<std::pair<std::string, CFDictionaryRef>>>
|
||||
BuildFiles;
|
||||
using TargetMap = std::unordered_map<std::string, CFDictionaryRef>;
|
||||
using DependencyMap = std::unordered_map<std::string, std::vector<std::string>>;
|
||||
using FileMap =
|
||||
std::unordered_map<std::string, std::vector<std::pair<std::string, CFDictionaryRef>>>;
|
||||
|
||||
static size_t totalFilesCount(const std::string& target,
|
||||
const Dependencies& dependencies,
|
||||
const BuildFiles& buildFiles) {
|
||||
const DependencyMap& dependencies,
|
||||
const FileMap& buildFiles) {
|
||||
size_t sum = buildFiles.at(target).size();
|
||||
for (auto& dep : dependencies.at(target)) {
|
||||
sum += totalFilesCount(dep, dependencies, buildFiles);
|
||||
@@ -61,9 +48,9 @@ static bool objectIsTarget(CFDictionaryRef object) {
|
||||
|
||||
static void mapTargetsToSourceFiles(CFDictionaryRef objects,
|
||||
std::unordered_map<std::string, size_t>& fileCounts) {
|
||||
Targets targets;
|
||||
Dependencies dependencies;
|
||||
BuildFiles buildFiles;
|
||||
TargetMap targets;
|
||||
DependencyMap dependencies;
|
||||
FileMap buildFiles;
|
||||
|
||||
auto kv = CFKeyValues::fromDictionary(objects);
|
||||
for (size_t i = 0; i < kv.size; i++) {
|
||||
@@ -213,42 +200,54 @@ static std::unordered_map<std::string, TargetData> mapTargetsToWorkspace(
|
||||
static std::vector<fs::path> collectFiles(const std::string& workingDir) {
|
||||
fs::path workDir(workingDir);
|
||||
std::vector<fs::path> files;
|
||||
auto iterator = fs::recursive_directory_iterator(workDir);
|
||||
auto end = fs::recursive_directory_iterator();
|
||||
for (; iterator != end; iterator++) {
|
||||
auto filename = iterator->path().filename();
|
||||
if (filename == "DerivedData" || filename == ".git" || filename == "build") {
|
||||
for (auto it = fs::recursive_directory_iterator(workDir); it != end; ++it) {
|
||||
const auto& p = it->path();
|
||||
if (p.filename() == "Package.swift") {
|
||||
files.push_back(p);
|
||||
continue;
|
||||
}
|
||||
if (!it->is_directory()) {
|
||||
continue;
|
||||
}
|
||||
if (p.filename() == "DerivedData" || p.filename() == ".git" || p.filename() == "build") {
|
||||
// Skip these folders
|
||||
iterator.disable_recursion_pending();
|
||||
it.disable_recursion_pending();
|
||||
continue;
|
||||
}
|
||||
auto dirEntry = *iterator;
|
||||
if (!dirEntry.is_directory()) {
|
||||
continue;
|
||||
if (p.extension() == ".xcodeproj" || p.extension() == ".xcworkspace") {
|
||||
files.push_back(p);
|
||||
}
|
||||
if (dirEntry.path().extension() != fs::path(".xcodeproj") &&
|
||||
dirEntry.path().extension() != fs::path(".xcworkspace")) {
|
||||
continue;
|
||||
}
|
||||
files.push_back(dirEntry.path());
|
||||
}
|
||||
return files;
|
||||
}
|
||||
|
||||
static std::unordered_map<std::string, std::vector<std::string>> collectWorkspaces(
|
||||
const std::string& workingDir) {
|
||||
const std::string& workingDir,
|
||||
bool& swiftPackageEncountered) {
|
||||
// Here we are collecting list of all workspaces and Xcode projects corresponding to them
|
||||
// Projects without workspaces go into the same "empty-workspace" bucket
|
||||
swiftPackageEncountered = false;
|
||||
std::unordered_map<std::string, std::vector<std::string>> workspaces;
|
||||
std::unordered_set<std::string> projectsBelongingToWorkspace;
|
||||
std::vector<fs::path> files = collectFiles(workingDir);
|
||||
for (auto& path : files) {
|
||||
std::cerr << path.c_str() << '\n';
|
||||
if (path.extension() == ".xcworkspace") {
|
||||
auto projects = readProjectsFromWorkspace(path.string());
|
||||
for (auto& project : projects) {
|
||||
projectsBelongingToWorkspace.insert(project.string());
|
||||
workspaces[path.string()].push_back(project.string());
|
||||
}
|
||||
} else if (!swiftPackageEncountered && path.filename() == "Package.swift") {
|
||||
// a package manifest must begin with a specific header comment
|
||||
// see https://docs.swift.org/package-manager/PackageDescription/PackageDescription.html
|
||||
static constexpr std::string_view packageHeader = "// swift-tools-version:";
|
||||
char buffer[packageHeader.size()];
|
||||
if (std::ifstream{path}.read(buffer, packageHeader.size()) && buffer == packageHeader) {
|
||||
swiftPackageEncountered = true;
|
||||
}
|
||||
std::cerr << " " << std::string_view{buffer} << '\n';
|
||||
}
|
||||
}
|
||||
// Collect all projects not belonging to any workspace into a separate empty bucket
|
||||
@@ -263,12 +262,13 @@ static std::unordered_map<std::string, std::vector<std::string>> collectWorkspac
|
||||
return workspaces;
|
||||
}
|
||||
|
||||
std::vector<Target> collectTargets(const std::string& workingDir) {
|
||||
Targets collectTargets(const std::string& workingDir) {
|
||||
Targets ret;
|
||||
// Getting a list of workspaces and the project that belong to them
|
||||
auto workspaces = collectWorkspaces(workingDir);
|
||||
if (workspaces.empty()) {
|
||||
DIAGNOSE_ERROR(no_project_found, "No Xcode project or workspace was found");
|
||||
exit(1);
|
||||
auto workspaces = collectWorkspaces(workingDir, ret.swiftPackageEncountered);
|
||||
ret.xcodeEncountered = !workspaces.empty();
|
||||
if (!ret.xcodeEncountered) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Mapping each target to the workspace/project it belongs to
|
||||
@@ -277,11 +277,9 @@ std::vector<Target> collectTargets(const std::string& workingDir) {
|
||||
// Mapping each target to the number of source files it contains
|
||||
auto targetFilesMapping = mapTargetsToSourceFiles(workspaces);
|
||||
|
||||
std::vector<Target> targets;
|
||||
|
||||
for (auto& [targetName, data] : targetMapping) {
|
||||
targets.push_back(Target{data.workspace, data.project, targetName, data.type,
|
||||
targetFilesMapping[targetName]});
|
||||
ret.targets.push_back(Target{data.workspace, data.project, targetName, data.type,
|
||||
targetFilesMapping[targetName]});
|
||||
}
|
||||
return targets;
|
||||
return ret;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user