Skip to content

Commit

Permalink
Merge pull request #673 from DustinCampbell/fix-dotnet-project-search
Browse files Browse the repository at this point in the history
Fix project.json search in DotNetProjectSystem
  • Loading branch information
DustinCampbell authored Nov 23, 2016
2 parents 58767a2 + c09300d commit a4dced2
Show file tree
Hide file tree
Showing 9 changed files with 243 additions and 157 deletions.
54 changes: 5 additions & 49 deletions src/OmniSharp.DotNet/DotNetWorkspace.cs
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Microsoft.DotNet.ProjectModel;
using Microsoft.DotNet.ProjectModel.Graph;
using OmniSharp.DotNet.Projects;

namespace OmniSharp.DotNet
{

public class DotNetWorkspace : Workspace
{
private readonly HashSet<string> _projects = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
Expand All @@ -16,13 +15,9 @@ public class DotNetWorkspace : Workspace

public DotNetWorkspace(string initialPath) : base(ProjectReaderSettings.ReadFromEnvironment(), true)
{
var paths = ResolveProjectPath(initialPath);
if (paths != null && paths.Any())
foreach (var path in ProjectSearcher.Search(initialPath))
{
foreach (var path in paths)
{
AddProject(path);
}
AddProject(path);
}
}

Expand Down Expand Up @@ -50,7 +45,7 @@ public IReadOnlyList<string> GetAllProjects()
public IReadOnlyList<ProjectContext> GetProjectContexts(string projectPath)
{
return (IReadOnlyList<ProjectContext>)GetProjectContextCollection(projectPath)?.ProjectContexts.AsReadOnly() ??
Enumerable.Empty<ProjectContext>().ToList().AsReadOnly();
Array.Empty<ProjectContext>();
}

/// <summary>
Expand Down Expand Up @@ -103,45 +98,6 @@ protected override IEnumerable<ProjectContext> BuildProjectContexts(Project proj
}
}

private static List<string> ResolveProjectPath(string projectPath)
{
if (File.Exists(projectPath))
{
var filename = Path.GetFileName(projectPath);
if (!Project.FileName.Equals(filename, StringComparison.OrdinalIgnoreCase) &&
!GlobalSettings.FileName.Equals(filename, StringComparison.OrdinalIgnoreCase))
{
return null;
}

projectPath = Path.GetDirectoryName(projectPath);
}

if (File.Exists(Path.Combine(projectPath, Project.FileName)))
{
return new List<string> { projectPath };
}

if (File.Exists(Path.Combine(projectPath, GlobalSettings.FileName)))
{
var root = ProjectRootResolver.ResolveRootDirectory(projectPath);
GlobalSettings globalSettings;
if (GlobalSettings.TryGetGlobalSettings(projectPath, out globalSettings))
{
return globalSettings.ProjectSearchPaths
.Select(searchPath => Path.Combine(globalSettings.DirectoryPath, searchPath))
.Where(actualPath => Directory.Exists(actualPath))
.SelectMany(actualPath => Directory.GetDirectories(actualPath))
.Where(actualPath => File.Exists(Path.Combine(actualPath, Project.FileName)))
.Select(path => Path.GetFullPath(path))
.Distinct(StringComparer.OrdinalIgnoreCase)
.ToList();
}
}

return null;
}

private static IEnumerable<ProjectDescription> GetProjectReferences(ProjectContext context)
{
var projectDescriptions = context.LibraryManager
Expand All @@ -156,7 +112,7 @@ private static IEnumerable<ProjectDescription> GetProjectReferences(ProjectConte
continue;
}

// if this is an assembly reference then don't threat it as project reference
// if this is an assembly reference then don't treat it as project reference
if (!string.IsNullOrEmpty(description.TargetFrameworkInfo?.AssemblyPath))
{
continue;
Expand Down
117 changes: 78 additions & 39 deletions src/OmniSharp.DotNet/Projects/ProjectSearcher.cs
Original file line number Diff line number Diff line change
@@ -1,66 +1,86 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Microsoft.DotNet.ProjectModel;

namespace OmniSharp.DotNet.Projects
{
public class ProjectSearcher
{
public static IEnumerable<string> Search(string solutionRoot)
public static IEnumerable<string> Search(string directory)
{
return Search(solutionRoot, maxDepth: 5);
return Search(directory, maxDepth: 5);
}

public static IEnumerable<string> Search(string solutionRoot, int maxDepth)
public static IEnumerable<string> Search(string directory, int maxDepth)
{
var dir = new DirectoryInfo(solutionRoot);
if (!dir.Exists)
if (!Directory.Exists(directory))
{
return Enumerable.Empty<string>();
return Array.Empty<string>();
}

if (File.Exists(Path.Combine(solutionRoot, Project.FileName)))
// Is there a project.json file in this directory? If so, return it.
var projectFilePath = Path.Combine(directory, Project.FileName);
if (File.Exists(projectFilePath))
{
return new string[] { solutionRoot };
return new string[] { projectFilePath };
}
else if (File.Exists(Path.Combine(solutionRoot, GlobalSettings.FileName)))

// Is there a global.json file in this directory? If so, use that to search.
if (File.Exists(Path.Combine(directory, GlobalSettings.FileName)))
{
return FindProjectsThroughGlobalJson(solutionRoot);
return FindProjectsThroughGlobalJson(directory);
}
else

// Otherwise, perform a general search through the file system.
return FindProjects(directory, maxDepth);
}

// TODO: Replace with proper tuple when we move to C# 7
private struct DirectoryAndDepth
{
public readonly string Directory;
public readonly int Depth;

private DirectoryAndDepth(string directory, int depth)
{
return FindProjects(solutionRoot, maxDepth);
this.Directory = directory;
this.Depth = depth;
}

public static DirectoryAndDepth Create(string directory, int depth)
=> new DirectoryAndDepth(directory, depth);
}

private static IEnumerable<string> FindProjects(string root, int maxDepth)
private static IEnumerable<string> FindProjects(string rootDirectory, int maxDepth)
{
var result = new List<string>();
var stack = new Stack<Tuple<DirectoryInfo, int>>();
var result = new SortedSet<string>(StringComparer.OrdinalIgnoreCase);
var stack = new Stack<DirectoryAndDepth>();

stack.Push(Tuple.Create(new DirectoryInfo(root), 0));
stack.Push(DirectoryAndDepth.Create(rootDirectory, 0));

while (stack.Any())
while (stack.Count > 0)
{
var next = stack.Pop();
var currentFolder = next.Item1;
var depth = next.Item2;
var current = stack.Pop();

if (!currentFolder.Exists)
if (!Directory.Exists(current.Directory))
{
continue;
}
else if (currentFolder.GetFiles(Project.FileName).Any())

// Did we find a project.json?
var projectFilePath = Path.Combine(current.Directory, Project.FileName);
if (File.Exists(projectFilePath))
{
result.Add(Path.Combine(currentFolder.FullName, Project.FileName));
result.Add(projectFilePath);
}
else if (depth < maxDepth)

// If we're not already at maximum depth, go ahead and search child directories.
if (current.Depth < maxDepth)
{
foreach (var sub in currentFolder.GetDirectories())
foreach (var childDirectory in Directory.GetDirectories(current.Directory))
{
stack.Push(Tuple.Create(sub, depth + 1));
stack.Push(DirectoryAndDepth.Create(childDirectory, current.Depth + 1));
}
}
}
Expand All @@ -73,19 +93,38 @@ private static IEnumerable<string> FindProjectsThroughGlobalJson(string root)
GlobalSettings globalSettings;
if (GlobalSettings.TryGetGlobalSettings(root, out globalSettings))
{
return globalSettings.ProjectSearchPaths
.Select(searchPath => Path.Combine(globalSettings.DirectoryPath, searchPath))
.Where(actualPath => Directory.Exists(actualPath))
.SelectMany(actualPath => Directory.GetDirectories(actualPath))
.Where(actualPath => File.Exists(Path.Combine(actualPath, Project.FileName)))
.Select(path => Path.GetFullPath(path))
.Distinct(StringComparer.OrdinalIgnoreCase)
.ToList();
}
else
{
return Enumerable.Empty<string>();
var projectPaths = new SortedSet<string>(StringComparer.OrdinalIgnoreCase);
var searchDirectories = new Queue<string>();

// Look in global.json 'projects' search paths and their immediate children
foreach (var searchPath in globalSettings.ProjectSearchPaths)
{
var searchDirectory = Path.Combine(globalSettings.DirectoryPath, searchPath);
if (Directory.Exists(searchDirectory))
{
searchDirectories.Enqueue(searchDirectory);

foreach (var childDirectory in Directory.GetDirectories(searchDirectory))
{
searchDirectories.Enqueue(childDirectory);
}
}
}

while (searchDirectories.Count > 0)
{
var searchDirectory = searchDirectories.Dequeue();
var projectFilePath = Path.Combine(searchDirectory, Project.FileName);
if (File.Exists(projectFilePath))
{
projectPaths.Add(Path.GetFullPath(projectFilePath));
}
}

return projectPaths;
}

return Array.Empty<string>();
}
}
}
62 changes: 0 additions & 62 deletions tests/OmniSharp.DotNet.Tests/ProjectSearcherTest.cs

This file was deleted.

Loading

0 comments on commit a4dced2

Please sign in to comment.