{"action":"created","comment":{"url":"https://api.github.com/repos/dotnet/cli/pulls/comments/45772306","id":45772306,"diff_hunk":"@@ -0,0 +1,328 @@\n+﻿// Copyright (c) .NET Foundation and contributors. All rights reserved.\n+// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n+\n+using System;\n+using System.Collections.Concurrent;\n+using System.Collections.Generic;\n+using System.IO;\n+using System.Linq;\n+using Microsoft.Extensions.ProjectModel;\n+using Microsoft.Extensions.ProjectModel.Graph;\n+using NuGet.Frameworks;\n+\n+namespace Microsoft.DotNet.ProjectModel.Workspace\n+{\n+    public class WorkspaceContext\n+    {\n+        // key: project directory\n+        private readonly ConcurrentDictionary<string, FileModelEntry<Project>> _projectsCache\n+                   = new ConcurrentDictionary<string, FileModelEntry<Project>>();\n+\n+        // key: project directory\n+        private readonly ConcurrentDictionary<string, FileModelEntry<LockFile>> _lockFileCache\n+                   = new ConcurrentDictionary<string, FileModelEntry<LockFile>>();\n+\n+        // key: project directory, target framework\n+        private readonly ConcurrentDictionary<Tuple<string, NuGetFramework>, ProjectContextEntry> _projectContextsCache\n+                   = new ConcurrentDictionary<Tuple<string, NuGetFramework>, ProjectContextEntry>();\n+\n+        private readonly HashSet<string> _projects = new HashSet<string>(StringComparer.OrdinalIgnoreCase);\n+\n+        private WorkspaceContext(List<string> projectPaths, string configuration)\n+        {\n+            Configuration = configuration;\n+            Initialize(projectPaths);\n+        }\n+\n+        public string Configuration { get; }\n+\n+        /// <summary>\n+        /// Create a WorkspaceContext from a given path.\n+        /// \n+        /// There must be either a global.json or project.json at under the given path. Otherwise\n+        /// null is returned.\n+        /// </summary>\n+        public static WorkspaceContext CreateFrom(string projectPath, string configuration)\n+        {\n+            var projectPaths = PathResolve(projectPath);\n+            if (projectPaths == null || !projectPaths.Any())\n+            {\n+                return null;\n+            }\n+\n+            var context = new WorkspaceContext(projectPaths, configuration);\n+            return context;\n+        }\n+\n+        public static WorkspaceContext CreateFrom(string projectPath)\n+        {\n+            return CreateFrom(projectPath, \"Debug\");\n+        }\n+\n+        private void Initialize(List<string> projectPaths)\n+        {\n+            _projects.Clear();\n+            foreach (var projectDirectory in projectPaths)\n+            {\n+                var project = GetProject(projectDirectory);\n+\n+                if (project == null)\n+                {\n+                    continue;\n+                }\n+\n+                _projects.Add(project.ProjectFilePath);\n+\n+                foreach (var framework in project.GetTargetFrameworks())\n+                {\n+                    var projectReferences = GetProjectReferences(project, framework.FrameworkName);\n+                    foreach (var eachReference in projectReferences)\n+                    {\n+                        var referencedProject = GetProject(eachReference.Path);\n+                        if (referencedProject == null)\n+                        {\n+                            continue;\n+                        }\n+\n+                        _projects.Add(referencedProject.ProjectFilePath);\n+                    }\n+                }\n+            }\n+        }\n+\n+        public IEnumerable<string> Projects => _projects;\n+\n+        public Project GetProject(string projectDirectory)\n+        {\n+            return _projectsCache.AddOrUpdate(\n+                projectDirectory,\n+                key => AddProjectEntry(key, null),\n+                (key, oldEntry) => AddProjectEntry(key, oldEntry)).Model;\n+        }\n+\n+        public LockFile GetLockFile(string projectDirectory)\n+        {\n+            return _lockFileCache.AddOrUpdate(\n+                projectDirectory,\n+                key => AddLockFileEntry(key, null),\n+                (key, oldEntry) => AddLockFileEntry(key, oldEntry)).Model;\n+        }\n+\n+        public ProjectContext GetProjectContext(Project project, NuGetFramework framework)\n+        {\n+            return _projectContextsCache.AddOrUpdate(\n+                Tuple.Create(project.ProjectDirectory, framework),\n+                key => AddProjectContextEntry(key.Item1, key.Item2, null),\n+                (key, oldEntry) => AddProjectContextEntry(key.Item1, key.Item2, oldEntry)).ProjectContext;\n+        }\n+\n+        public IEnumerable<DependencyDescription> GetDependencies(Project project, NuGetFramework framework)","path":"src/Microsoft.DotNet.ProjectModel/Workspace/WorkspaceContext.cs","position":119,"original_position":119,"commit_id":"42f713426e70347c91e32676c8e40608c52f6942","original_commit_id":"42f713426e70347c91e32676c8e40608c52f6942","user":{"login":"anurse","id":7574,"avatar_url":"https://avatars.githubusercontent.com/u/7574?v=3","gravatar_id":"","url":"https://api.github.com/users/anurse","html_url":"https://github.com/anurse","followers_url":"https://api.github.com/users/anurse/followers","following_url":"https://api.github.com/users/anurse/following{/other_user}","gists_url":"https://api.github.com/users/anurse/gists{/gist_id}","starred_url":"https://api.github.com/users/anurse/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/anurse/subscriptions","organizations_url":"https://api.github.com/users/anurse/orgs","repos_url":"https://api.github.com/users/anurse/repos","events_url":"https://api.github.com/users/anurse/events{/privacy}","received_events_url":"https://api.github.com/users/anurse/received_events","type":"User","site_admin":false},"body":"I thought these were going to hang off of `ProjectContext` directly. Then, only the `ProjectContext` itself really needs to be cached...","created_at":"2015-11-24T18:11:51Z","updated_at":"2015-11-24T18:11:51Z","html_url":"https://github.com/dotnet/cli/pull/277#discussion_r45772306","pull_request_url":"https://api.github.com/repos/dotnet/cli/pulls/277","_links":{"self":{"href":"https://api.github.com/repos/dotnet/cli/pulls/comments/45772306"},"html":{"href":"https://github.com/dotnet/cli/pull/277#discussion_r45772306"},"pull_request":{"href":"https://api.github.com/repos/dotnet/cli/pulls/277"}}},"pull_request":{"url":"https://api.github.com/repos/dotnet/cli/pulls/277","id":51332999,"html_url":"https://github.com/dotnet/cli/pull/277","diff_url":"https://github.com/dotnet/cli/pull/277.diff","patch_url":"https://github.com/dotnet/cli/pull/277.patch","issue_url":"https://api.github.com/repos/dotnet/cli/issues/277","number":277,"state":"open","locked":false,"title":"Add project system","user":{"login":"troydai","id":1329240,"avatar_url":"https://avatars.githubusercontent.com/u/1329240?v=3","gravatar_id":"","url":"https://api.github.com/users/troydai","html_url":"https://github.com/troydai","followers_url":"https://api.github.com/users/troydai/followers","following_url":"https://api.github.com/users/troydai/following{/other_user}","gists_url":"https://api.github.com/users/troydai/gists{/gist_id}","starred_url":"https://api.github.com/users/troydai/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/troydai/subscriptions","organizations_url":"https://api.github.com/users/troydai/orgs","repos_url":"https://api.github.com/users/troydai/repos","events_url":"https://api.github.com/users/troydai/events{/privacy}","received_events_url":"https://api.github.com/users/troydai/received_events","type":"User","site_admin":false},"body":"Issue: https://github.com/dotnet/cli/issues/175\r\n\r\nProject system API represents part of the original Design time host's\r\nfunction:\r\n1. Discover projects from a global.json\r\n2. Resolve references and dependencies\r\n3. Monitor changes to projects\r\n\r\nAn adoption of this API is in [OmniSharp](https://github.com/troydai/omnisharp-roslyn/commit/cb780c0b4333b4f25f72a96cb2d926aab814ae7b). The OmniSharp therefore can be mostly functional on CoreCLR without a separate out of process DTH.\r\n\r\nOpen question:\r\n1. A test case is added to cover the use case. However since we don't have established any automation in this repo yet it is open to discuss how we want the functional test to be organized.\r\n2. Naming, Naming, Naming.\r\n\r\nUnfinished:\r\n1. Discovering projects under a folder without global.json;\r\n2. Discovering through single project;\r\n3. Pooling the project.json object model to reduce allocation.","created_at":"2015-11-20T09:14:39Z","updated_at":"2015-11-24T18:11:51Z","closed_at":null,"merged_at":null,"merge_commit_sha":"6af4dfcc8b9c198303794ab81497e4976fb5c93f","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/dotnet/cli/pulls/277/commits","review_comments_url":"https://api.github.com/repos/dotnet/cli/pulls/277/comments","review_comment_url":"https://api.github.com/repos/dotnet/cli/pulls/comments{/number}","comments_url":"https://api.github.com/repos/dotnet/cli/issues/277/comments","statuses_url":"https://api.github.com/repos/dotnet/cli/statuses/42f713426e70347c91e32676c8e40608c52f6942","head":{"label":"dotnet:trdai/dth","ref":"trdai/dth","sha":"42f713426e70347c91e32676c8e40608c52f6942","user":{"login":"dotnet","id":9141961,"avatar_url":"https://avatars.githubusercontent.com/u/9141961?v=3","gravatar_id":"","url":"https://api.github.com/users/dotnet","html_url":"https://github.com/dotnet","followers_url":"https://api.github.com/users/dotnet/followers","following_url":"https://api.github.com/users/dotnet/following{/other_user}","gists_url":"https://api.github.com/users/dotnet/gists{/gist_id}","starred_url":"https://api.github.com/users/dotnet/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/dotnet/subscriptions","organizations_url":"https://api.github.com/users/dotnet/orgs","repos_url":"https://api.github.com/users/dotnet/repos","events_url":"https://api.github.com/users/dotnet/events{/privacy}","received_events_url":"https://api.github.com/users/dotnet/received_events","type":"Organization","site_admin":false},"repo":{"id":43568107,"name":"cli","full_name":"dotnet/cli","owner":{"login":"dotnet","id":9141961,"avatar_url":"https://avatars.githubusercontent.com/u/9141961?v=3","gravatar_id":"","url":"https://api.github.com/users/dotnet","html_url":"https://github.com/dotnet","followers_url":"https://api.github.com/users/dotnet/followers","following_url":"https://api.github.com/users/dotnet/following{/other_user}","gists_url":"https://api.github.com/users/dotnet/gists{/gist_id}","starred_url":"https://api.github.com/users/dotnet/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/dotnet/subscriptions","organizations_url":"https://api.github.com/users/dotnet/orgs","repos_url":"https://api.github.com/users/dotnet/repos","events_url":"https://api.github.com/users/dotnet/events{/privacy}","received_events_url":"https://api.github.com/users/dotnet/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/dotnet/cli","description":"This repo contains the .NET Core command-line (CLI) tools, used for building .NET Core apps and libraries through your development flow (compiling, NuGet package management, running, testing, ...).","fork":false,"url":"https://api.github.com/repos/dotnet/cli","forks_url":"https://api.github.com/repos/dotnet/cli/forks","keys_url":"https://api.github.com/repos/dotnet/cli/keys{/key_id}","collaborators_url":"https://api.github.com/repos/dotnet/cli/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/dotnet/cli/teams","hooks_url":"https://api.github.com/repos/dotnet/cli/hooks","issue_events_url":"https://api.github.com/repos/dotnet/cli/issues/events{/number}","events_url":"https://api.github.com/repos/dotnet/cli/events","assignees_url":"https://api.github.com/repos/dotnet/cli/assignees{/user}","branches_url":"https://api.github.com/repos/dotnet/cli/branches{/branch}","tags_url":"https://api.github.com/repos/dotnet/cli/tags","blobs_url":"https://api.github.com/repos/dotnet/cli/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/dotnet/cli/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/dotnet/cli/git/refs{/sha}","trees_url":"https://api.github.com/repos/dotnet/cli/git/trees{/sha}","statuses_url":"https://api.github.com/repos/dotnet/cli/statuses/{sha}","languages_url":"https://api.github.com/repos/dotnet/cli/languages","stargazers_url":"https://api.github.com/repos/dotnet/cli/stargazers","contributors_url":"https://api.github.com/repos/dotnet/cli/contributors","subscribers_url":"https://api.github.com/repos/dotnet/cli/subscribers","subscription_url":"https://api.github.com/repos/dotnet/cli/subscription","commits_url":"https://api.github.com/repos/dotnet/cli/commits{/sha}","git_commits_url":"https://api.github.com/repos/dotnet/cli/git/commits{/sha}","comments_url":"https://api.github.com/repos/dotnet/cli/comments{/number}","issue_comment_url":"https://api.github.com/repos/dotnet/cli/issues/comments{/number}","contents_url":"https://api.github.com/repos/dotnet/cli/contents/{+path}","compare_url":"https://api.github.com/repos/dotnet/cli/compare/{base}...{head}","merges_url":"https://api.github.com/repos/dotnet/cli/merges","archive_url":"https://api.github.com/repos/dotnet/cli/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/dotnet/cli/downloads","issues_url":"https://api.github.com/repos/dotnet/cli/issues{/number}","pulls_url":"https://api.github.com/repos/dotnet/cli/pulls{/number}","milestones_url":"https://api.github.com/repos/dotnet/cli/milestones{/number}","notifications_url":"https://api.github.com/repos/dotnet/cli/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/dotnet/cli/labels{/name}","releases_url":"https://api.github.com/repos/dotnet/cli/releases{/id}","created_at":"2015-10-02T18:03:15Z","updated_at":"2015-11-24T15:39:21Z","pushed_at":"2015-11-24T09:00:58Z","git_url":"git://github.com/dotnet/cli.git","ssh_url":"git@github.com:dotnet/cli.git","clone_url":"https://github.com/dotnet/cli.git","svn_url":"https://github.com/dotnet/cli","homepage":"http://dotnet.github.io/","size":13887,"stargazers_count":106,"watchers_count":106,"language":"C#","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":16,"mirror_url":null,"open_issues_count":133,"forks":16,"open_issues":133,"watchers":106,"default_branch":"master"}},"base":{"label":"dotnet:master","ref":"master","sha":"d91a4f32e6ebe0dd3cb48fb915acbbbc48705069","user":{"login":"dotnet","id":9141961,"avatar_url":"https://avatars.githubusercontent.com/u/9141961?v=3","gravatar_id":"","url":"https://api.github.com/users/dotnet","html_url":"https://github.com/dotnet","followers_url":"https://api.github.com/users/dotnet/followers","following_url":"https://api.github.com/users/dotnet/following{/other_user}","gists_url":"https://api.github.com/users/dotnet/gists{/gist_id}","starred_url":"https://api.github.com/users/dotnet/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/dotnet/subscriptions","organizations_url":"https://api.github.com/users/dotnet/orgs","repos_url":"https://api.github.com/users/dotnet/repos","events_url":"https://api.github.com/users/dotnet/events{/privacy}","received_events_url":"https://api.github.com/users/dotnet/received_events","type":"Organization","site_admin":false},"repo":{"id":43568107,"name":"cli","full_name":"dotnet/cli","owner":{"login":"dotnet","id":9141961,"avatar_url":"https://avatars.githubusercontent.com/u/9141961?v=3","gravatar_id":"","url":"https://api.github.com/users/dotnet","html_url":"https://github.com/dotnet","followers_url":"https://api.github.com/users/dotnet/followers","following_url":"https://api.github.com/users/dotnet/following{/other_user}","gists_url":"https://api.github.com/users/dotnet/gists{/gist_id}","starred_url":"https://api.github.com/users/dotnet/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/dotnet/subscriptions","organizations_url":"https://api.github.com/users/dotnet/orgs","repos_url":"https://api.github.com/users/dotnet/repos","events_url":"https://api.github.com/users/dotnet/events{/privacy}","received_events_url":"https://api.github.com/users/dotnet/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/dotnet/cli","description":"This repo contains the .NET Core command-line (CLI) tools, used for building .NET Core apps and libraries through your development flow (compiling, NuGet package management, running, testing, ...).","fork":false,"url":"https://api.github.com/repos/dotnet/cli","forks_url":"https://api.github.com/repos/dotnet/cli/forks","keys_url":"https://api.github.com/repos/dotnet/cli/keys{/key_id}","collaborators_url":"https://api.github.com/repos/dotnet/cli/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/dotnet/cli/teams","hooks_url":"https://api.github.com/repos/dotnet/cli/hooks","issue_events_url":"https://api.github.com/repos/dotnet/cli/issues/events{/number}","events_url":"https://api.github.com/repos/dotnet/cli/events","assignees_url":"https://api.github.com/repos/dotnet/cli/assignees{/user}","branches_url":"https://api.github.com/repos/dotnet/cli/branches{/branch}","tags_url":"https://api.github.com/repos/dotnet/cli/tags","blobs_url":"https://api.github.com/repos/dotnet/cli/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/dotnet/cli/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/dotnet/cli/git/refs{/sha}","trees_url":"https://api.github.com/repos/dotnet/cli/git/trees{/sha}","statuses_url":"https://api.github.com/repos/dotnet/cli/statuses/{sha}","languages_url":"https://api.github.com/repos/dotnet/cli/languages","stargazers_url":"https://api.github.com/repos/dotnet/cli/stargazers","contributors_url":"https://api.github.com/repos/dotnet/cli/contributors","subscribers_url":"https://api.github.com/repos/dotnet/cli/subscribers","subscription_url":"https://api.github.com/repos/dotnet/cli/subscription","commits_url":"https://api.github.com/repos/dotnet/cli/commits{/sha}","git_commits_url":"https://api.github.com/repos/dotnet/cli/git/commits{/sha}","comments_url":"https://api.github.com/repos/dotnet/cli/comments{/number}","issue_comment_url":"https://api.github.com/repos/dotnet/cli/issues/comments{/number}","contents_url":"https://api.github.com/repos/dotnet/cli/contents/{+path}","compare_url":"https://api.github.com/repos/dotnet/cli/compare/{base}...{head}","merges_url":"https://api.github.com/repos/dotnet/cli/merges","archive_url":"https://api.github.com/repos/dotnet/cli/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/dotnet/cli/downloads","issues_url":"https://api.github.com/repos/dotnet/cli/issues{/number}","pulls_url":"https://api.github.com/repos/dotnet/cli/pulls{/number}","milestones_url":"https://api.github.com/repos/dotnet/cli/milestones{/number}","notifications_url":"https://api.github.com/repos/dotnet/cli/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/dotnet/cli/labels{/name}","releases_url":"https://api.github.com/repos/dotnet/cli/releases{/id}","created_at":"2015-10-02T18:03:15Z","updated_at":"2015-11-24T15:39:21Z","pushed_at":"2015-11-24T09:00:58Z","git_url":"git://github.com/dotnet/cli.git","ssh_url":"git@github.com:dotnet/cli.git","clone_url":"https://github.com/dotnet/cli.git","svn_url":"https://github.com/dotnet/cli","homepage":"http://dotnet.github.io/","size":13887,"stargazers_count":106,"watchers_count":106,"language":"C#","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":16,"mirror_url":null,"open_issues_count":133,"forks":16,"open_issues":133,"watchers":106,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/dotnet/cli/pulls/277"},"html":{"href":"https://github.com/dotnet/cli/pull/277"},"issue":{"href":"https://api.github.com/repos/dotnet/cli/issues/277"},"comments":{"href":"https://api.github.com/repos/dotnet/cli/issues/277/comments"},"review_comments":{"href":"https://api.github.com/repos/dotnet/cli/pulls/277/comments"},"review_comment":{"href":"https://api.github.com/repos/dotnet/cli/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/dotnet/cli/pulls/277/commits"},"statuses":{"href":"https://api.github.com/repos/dotnet/cli/statuses/42f713426e70347c91e32676c8e40608c52f6942"}}}}