diff --git a/internal/codeintel/autoindexing/internal/inference/BUILD.bazel b/internal/codeintel/autoindexing/internal/inference/BUILD.bazel index a38528cec49..95e6dda2dd1 100644 --- a/internal/codeintel/autoindexing/internal/inference/BUILD.bazel +++ b/internal/codeintel/autoindexing/internal/inference/BUILD.bazel @@ -50,6 +50,7 @@ go_test( timeout = "short", srcs = [ "infer_test.go", + "lang_dotnet_test.go", "lang_go_test.go", "lang_java_test.go", "lang_python_test.go", diff --git a/internal/codeintel/autoindexing/internal/inference/lang_dotnet_test.go b/internal/codeintel/autoindexing/internal/inference/lang_dotnet_test.go new file mode 100644 index 00000000000..f26199f9998 --- /dev/null +++ b/internal/codeintel/autoindexing/internal/inference/lang_dotnet_test.go @@ -0,0 +1,26 @@ +package inference + +import ( + "testing" +) + +func TestDotNetGenerator(t *testing.T) { + testGenerators(t, + generatorTestCase{ + description: "dotnet sln files exist", + repositoryContents: map[string]string{ + "one.sln": "", + "one.csproj": "", + "foo/baz/two.sln": "", + "foo/baz/two.vbproj": "", + }, + }, + generatorTestCase{ + description: "dotnet sln files do not exist", + repositoryContents: map[string]string{ + "one.csproj": "", + "foo/baz/two.vbproj": "", + }, + }, + ) +} diff --git a/internal/codeintel/autoindexing/internal/inference/libs/indexes.go b/internal/codeintel/autoindexing/internal/inference/libs/indexes.go index 4571f3ae4d2..a66a2fbd555 100644 --- a/internal/codeintel/autoindexing/internal/inference/libs/indexes.go +++ b/internal/codeintel/autoindexing/internal/inference/libs/indexes.go @@ -22,6 +22,7 @@ var defaultIndexers = map[string]string{ "rust": "sourcegraph/scip-rust", "typescript": "sourcegraph/scip-typescript", "ruby": "sourcegraph/scip-ruby", + "dotnet": "sourcegraph/scip-dotnet", } // To update, run `DOCKER_USER=... DOCKER_PASS=... ./update-shas.sh` @@ -32,6 +33,7 @@ var defaultIndexerSHAs = map[string]string{ "sourcegraph/scip-python": "sha256:e3c13f0cadca78098439c541d19a72c21672a3263e22aa706760d941581e068d", "sourcegraph/scip-typescript": "sha256:3df8b36a2ad4e073415bfbeaedf38b3cfff3e697614c8f578299f470d140c2c8", "sourcegraph/scip-ruby": "sha256:ef53e5f1450330ddb4a3edce963b7e10d900d44ff1e7de4960680289ac25f319", + "sourcegraph/scip-dotnet": "sha256:1d8a590edfb3834020fceedacac6608811dd31fcba9092426140093876d8d52e", } func DefaultIndexerForLang(language string) (string, bool) { diff --git a/internal/codeintel/autoindexing/internal/inference/libs/update-shas.sh b/internal/codeintel/autoindexing/internal/inference/libs/update-shas.sh index 2c158b0a159..22d06d1008c 100755 --- a/internal/codeintel/autoindexing/internal/inference/libs/update-shas.sh +++ b/internal/codeintel/autoindexing/internal/inference/libs/update-shas.sh @@ -16,7 +16,7 @@ fi SCRIPT_DIR="$(dirname "${BASH_SOURCE[0]}")" # No scip-clang as that doesn't have a Docker image -for indexer in scip-go scip-rust scip-java scip-python scip-typescript scip-ruby; do +for indexer in scip-go scip-rust scip-java scip-python scip-typescript scip-ruby scip-dotnet; do tag="latest" if [[ "${indexer}" = "scip-python" ]] || [[ "${indexer}" = "scip-typescript" || "${indexer}" = "scip-ruby" ]]; then tag="autoindex" diff --git a/internal/codeintel/autoindexing/internal/inference/lua/BUILD.bazel b/internal/codeintel/autoindexing/internal/inference/lua/BUILD.bazel index ec6bd469a44..9d9e69edd25 100644 --- a/internal/codeintel/autoindexing/internal/inference/lua/BUILD.bazel +++ b/internal/codeintel/autoindexing/internal/inference/lua/BUILD.bazel @@ -8,6 +8,7 @@ go_library( "README.md", "config.lua", "embed.go", + "dotnet.lua", "go.lua", "indexes.lua", "java.lua", diff --git a/internal/codeintel/autoindexing/internal/inference/lua/dotnet.lua b/internal/codeintel/autoindexing/internal/inference/lua/dotnet.lua new file mode 100644 index 00000000000..07fc3fc6907 --- /dev/null +++ b/internal/codeintel/autoindexing/internal/inference/lua/dotnet.lua @@ -0,0 +1,65 @@ +local path = require("path") +local pattern = require("sg.autoindex.patterns") +local recognizer = require("sg.autoindex.recognizer") + +local indexer = require("sg.autoindex.indexes").get("dotnet") + +local env_steps = { + + -- macOS enables W^X (https://en.wikipedia.org/wiki/W%5EX) which means + -- that when running in development, we need to set the following environment + -- variable for `dotnet restore` to work correctly. It is technically not needed on + -- Linux in production, and removing this might improve performance, but we + -- currently do not have a way of conditionally passing in OS-level configuration + -- to the Lua script, and doing so would create a divergence between dev vs prod, + -- so leave this as-is for now. + -- + -- See also: https://github.com/dotnet/runtime/issues/97828 + "export DOTNET_EnableWriteXorExecute=0", +} + +local generate_dotnet_jobs = function(_, paths) + local jobs = {} + for i = 1, #paths do + table.insert(jobs, { + indexer = indexer, + root = path.dirname(paths[i]), + local_steps = env_steps, + indexer_args = { "scip-dotnet", "index", paths[i], "--output", "index.scip" }, + outfile = "index.scip", + }) + end + + return jobs +end + +local dotnet_proj_recognizer = recognizer.new_path_recognizer({ + patterns = { + pattern.new_path_extension("csproj"), + pattern.new_path_extension("vbproj"), + }, + + generate = generate_dotnet_jobs, +}) + +local dotnet_sln_recognizer = recognizer.new_path_recognizer({ + patterns = { + pattern.new_path_extension("sln"), + }, + + generate = generate_dotnet_jobs, +}) + +-- For .NET projects we are employing a fallback recognizer that will first +-- look for only solution files in a repo. This is the most common structure for .NET repos +-- and we will build an indexing job for each solution file we find. +-- If we find no solution files, we will then look for any .csproj or.vbproj files +-- and build an indexing job for each of them. This structure can happen since solution files are not required +-- and sometimes people auto-generate and don't version control them just for IDE support. +-- A repo with a more exotic structure, mixing projects that are part of solutions with +-- projects that are outside of solutions, would need to be indexed by the user manually +-- or have the user customize the inference. +return recognizer.new_fallback_recognizer({ + dotnet_sln_recognizer, + dotnet_proj_recognizer, +}) diff --git a/internal/codeintel/autoindexing/internal/inference/lua/recognizers.lua b/internal/codeintel/autoindexing/internal/inference/lua/recognizers.lua index 06343595627..82b81da15f9 100644 --- a/internal/codeintel/autoindexing/internal/inference/lua/recognizers.lua +++ b/internal/codeintel/autoindexing/internal/inference/lua/recognizers.lua @@ -1,6 +1,6 @@ -local config = require("sg.autoindex.config").new {} +local config = require("sg.autoindex.config").new({}) -for _, name in ipairs { +for _, name in ipairs({ "go", "java", "python", @@ -8,7 +8,8 @@ for _, name in ipairs { "rust", "test", "typescript", -} do + "dotnet", +}) do -- Backdoor set `sg.`-prefixed recognizers rawset(config, "sg." .. name, require("sg.autoindex." .. name)) end diff --git a/internal/codeintel/autoindexing/internal/inference/testdata/dotnet_sln_files_do_not_exist.yaml b/internal/codeintel/autoindexing/internal/inference/testdata/dotnet_sln_files_do_not_exist.yaml new file mode 100644 index 00000000000..55a3dcf2088 --- /dev/null +++ b/internal/codeintel/autoindexing/internal/inference/testdata/dotnet_sln_files_do_not_exist.yaml @@ -0,0 +1,26 @@ +- steps: [] + local_steps: + - export DOTNET_EnableWriteXorExecute=0 + root: "" + indexer: sourcegraph/scip-dotnet@sha256:1d8a590edfb3834020fceedacac6608811dd31fcba9092426140093876d8d52e + indexer_args: + - scip-dotnet + - index + - one.csproj + - --output + - index.scip + outfile: index.scip + requestedEnvVars: [] +- steps: [] + local_steps: + - export DOTNET_EnableWriteXorExecute=0 + root: foo/baz + indexer: sourcegraph/scip-dotnet@sha256:1d8a590edfb3834020fceedacac6608811dd31fcba9092426140093876d8d52e + indexer_args: + - scip-dotnet + - index + - foo/baz/two.vbproj + - --output + - index.scip + outfile: index.scip + requestedEnvVars: [] diff --git a/internal/codeintel/autoindexing/internal/inference/testdata/dotnet_sln_files_exist.yaml b/internal/codeintel/autoindexing/internal/inference/testdata/dotnet_sln_files_exist.yaml new file mode 100644 index 00000000000..98f78bcb6b3 --- /dev/null +++ b/internal/codeintel/autoindexing/internal/inference/testdata/dotnet_sln_files_exist.yaml @@ -0,0 +1,26 @@ +- steps: [] + local_steps: + - export DOTNET_EnableWriteXorExecute=0 + root: "" + indexer: sourcegraph/scip-dotnet@sha256:1d8a590edfb3834020fceedacac6608811dd31fcba9092426140093876d8d52e + indexer_args: + - scip-dotnet + - index + - one.sln + - --output + - index.scip + outfile: index.scip + requestedEnvVars: [] +- steps: [] + local_steps: + - export DOTNET_EnableWriteXorExecute=0 + root: foo/baz + indexer: sourcegraph/scip-dotnet@sha256:1d8a590edfb3834020fceedacac6608811dd31fcba9092426140093876d8d52e + indexer_args: + - scip-dotnet + - index + - foo/baz/two.sln + - --output + - index.scip + outfile: index.scip + requestedEnvVars: [] diff --git a/internal/codeintel/autoindexing/internal/store/config_inference.go b/internal/codeintel/autoindexing/internal/store/config_inference.go index be5a26c9854..92291da24e1 100644 --- a/internal/codeintel/autoindexing/internal/store/config_inference.go +++ b/internal/codeintel/autoindexing/internal/store/config_inference.go @@ -92,6 +92,7 @@ return require("sg.autoindex.config").new({ -- ["sg.ruby"] = false, -- ["sg.rust"] = false, -- ["sg.typescript"] = false, + -- ["sg.dotnet"] = false, ["acme.custom"] = custom_recognizer, }) `