1 module more.repos;
2 
3 import std.array;
4 import std.path : dirSeparator, globMatch;
5 import std.file;
6 
7 import core.stdc.stdlib : alloca;
8 
9 import more.fields;
10 import more.path;
11 
12 immutable gitDir = ".git";
13 
14 /**
15    Checks to see if the given path is inside a git repo.
16    It does this by checking for the '.git' directory in the given directory and every
17    parent directory.
18    Returns: The path to the root of the git repo, or null if not inside a git repo.
19  */
20 string insideGitRepo(string path = getcwd()) nothrow @nogc
21 {
22     auto pathBuffer = cast(char*)alloca(path.length + 1 + gitDir.length);
23 
24     char[] addGitDir(size_t s) nothrow @nogc
25     {
26         if(pathBuffer[s-1] == dirSeparator[0])
27         {
28             pathBuffer[s..s+gitDir.length] = gitDir;
29             return pathBuffer[0..s+gitDir.length];
30         }
31         else
32         {
33             pathBuffer[s] = dirSeparator[0];
34             pathBuffer[s+1..s+1+gitDir.length] = gitDir;
35             return pathBuffer[0..s+1+gitDir.length];
36         }
37     }
38 
39     pathBuffer[0..path.length] = path;
40     auto gitPath = addGitDir(path.length);
41 
42     while(true)
43     {
44         auto currentDir = gitPath[0..$-gitDir.length-1];
45         //import core.stdc.stdio;
46         //printf("checking '%.*s'\n", gitPath.length, gitPath.ptr);
47         if(exists(gitPath))
48         {
49             return path[0..currentDir.length];
50         }
51 
52         auto newCheckPath = parentDir(currentDir);
53         if(newCheckPath.length == currentDir.length)
54         {
55             return null;
56         }
57 
58         gitPath = addGitDir(newCheckPath.length);
59     }
60 }
61 
62 struct Repo
63 {
64     string localPath;
65     //string keyPath; //
66 
67     string globMatcher;
68 
69     void setupGlobMatcher()
70     {
71         this.globMatcher = localPath;
72     }
73     bool contains(string file)
74     {
75         if(globMatcher is null)
76         {
77             setupGlobMatcher();
78         }
79         return globMatch(globMatcher, file);
80     }
81 }
82 
83 struct RepoSet
84 {
85     Appender!(Repo[]) repos;
86 
87     bool pathBelongsToKnownRepo(string path, ref Repo foundRepo)
88     {
89         foreach(repo; repos.data)
90         {
91             if(repo.contains(path))
92             {
93                 foundRepo = repo;
94                 return true;
95             }
96         }
97         return false;
98     }
99 }
100 RepoSet knownRepos;
101 
102 /**
103 Find Repo Algorithm:
104   1. Check if you are inside a git repository, if you are get out.
105   2. search the given directory for sub directories with the same name as the repo.
106      If the repo name matches, it checks if it is a repo, if it is, then the repo is found.
107   3. It checks for a file named "repos".  If it exists it reads the file and searches to
108      see if it contains the definition for the repo.
109   4. It goes through every parent directory checking the sub directories again for the repo name.
110  */
111 Repo findRepo(string repoName, string path = null)
112 {
113     if(path.length <= 0)
114     {
115         path = getcwd();
116     }
117     else
118     {
119 
120     }
121 
122     Repo currentRepo;
123 
124     if(knownRepos.pathBelongsToKnownRepo(path, currentRepo))
125     {
126     path = currentRepo.localPath;
127     }
128 
129 
130 
131     return Repo();
132     /+
133 
134 
135     foreach(entry; dirEntries(path, SpanMode.shallow)) {
136     if(
137     }
138     +/
139 }