1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
namespace SourceBrowser.Site.Controllers
{
    using System.IO;
    using System.Web.Mvc;
    using SourceBrowser.SolutionRetriever;
    using SourceBrowser.Generator.Transformers;
    using SourceBrowser.Site.Repositories;
    using System;
    using System.Linq;

    public class UploadController : Controller
    {
        // GET: Upload
        public ActionResult Index()
        {
            return View();
        }

        public ActionResult Submit(string githubUrl)
        {
            // If someone navigates to submit directly, just send 'em back to index
            if (string.IsNullOrWhiteSpace(githubUrl))
            {
                return View("Index");
            }

            var retriever = new GitHubRetriever(githubUrl);
            if (!retriever.IsValidUrl())
            {
                ViewBag.Error = "Make sure that the provided path points to a valid GitHub repository.";
                return View("Index");
            }

            // Check if this repo already exists
            if (!BrowserRepository.TryLockRepository(retriever.UserName, retriever.RepoName))
            {
	            // Repo exists. Redirect the user to that repository.
	            return Redirect("/Browse/" + retriever.UserName + "/" + retriever.RepoName);
            }
            // We have locked the repository and marked it as processing.
            // Whenever we return or exit on an exception, we need to unlock this repository
            bool processingSuccessful = false;
            try
            {
                string repoRootPath = string.Empty;
                try
                {
                    repoRootPath = retriever.RetrieveProject();
                }
                catch (Exception ex)
                {
                    ViewBag.Error = "There was an error downloading this repository.";
                    return View("Index");
                }

                // Generate the source browser files for this solution
                var solutionPaths = GetSolutionPaths(repoRootPath);
                if (solutionPaths.Length == 0)
                {
                    ViewBag.Error = "No C# solution was found. Ensure that a valid .sln file exists within your repository.";
                    return View("Index");
                }

                var organizationPath = System.Web.Hosting.HostingEnvironment.MapPath("~/") + "SB_Files\\" + retriever.UserName;
                var repoPath = Path.Combine(organizationPath, retriever.RepoName);

                // TODO: Use parallel for.
                // TODO: Process all solutions.
                // For now, we're assuming the shallowest and shortest .sln file is the one we're interested in
                foreach (var solutionPath in solutionPaths.OrderBy(n => n.Length).Take(1))
                {
                    try
                    {
                        var workspaceModel = UploadRepository.ProcessSolution(solutionPath, repoRootPath);

                        //One pass to lookup all declarations
                        var typeTransformer = new TokenLookupTransformer();
                        typeTransformer.Visit(workspaceModel);
                        var tokenLookup = typeTransformer.TokenLookup;

                        //Another pass to generate HTMLs
                        var htmlTransformer = new HtmlTransformer(tokenLookup, repoPath);
                        htmlTransformer.Visit(workspaceModel);

                        var searchTransformer = new SearchIndexTransformer(retriever.UserName, retriever.RepoName);
                        searchTransformer.Visit(workspaceModel);

                        // Generate HTML of the tree view
                        var treeViewTransformer = new TreeViewTransformer(repoPath, retriever.UserName, retriever.RepoName);
                        treeViewTransformer.Visit(workspaceModel);
                    }
                    catch (Exception ex)
                    {
                        // TODO: Log this
                        ViewBag.Error = "There was an error processing solution " + Path.GetFileName(solutionPath);
                        return View("Index");
                    }
                }

                try
                {
                    UploadRepository.SaveReadme(repoPath, retriever.ProvideParsedReadme());
                }
                catch (Exception ex)
                {
                    // TODO: Log and swallow - readme is not essential.
                }

                processingSuccessful = true;
                return Redirect("/Browse/" + retriever.UserName + "/" + retriever.RepoName);
            }
            finally
            {
                if (processingSuccessful)
                {
                    BrowserRepository.UnlockRepository(retriever.UserName, retriever.RepoName);
                }
                else
                {
                    BrowserRepository.RemoveRepository(retriever.UserName, retriever.RepoName);
                }
            }
        }

        /// <summary>
        /// Simply searches for the solution files and returns their paths.
        /// </summary>
        /// <param name="rootDirectory">
        /// The root Directory.
        /// </param>
        /// <returns>
        /// The solution paths.
        /// </returns>
        private string[] GetSolutionPaths(string rootDirectory)
        {
            return Directory.GetFiles(rootDirectory, "*.sln", SearchOption.AllDirectories);
        }
    }
}