|
2 | 2 | using System.ComponentModel.Composition; |
3 | 3 | using System.IO; |
4 | 4 | using System.Linq; |
| 5 | +using System.Diagnostics; |
5 | 6 | using GitHub.Models; |
6 | 7 | using System.Reactive.Linq; |
7 | 8 | using Rothko; |
@@ -103,13 +104,44 @@ public IObservable<IReadOnlyList<CommitMessage>> GetMessagesForUniqueCommits( |
103 | 104 | }); |
104 | 105 | } |
105 | 106 |
|
| 107 | + public IObservable<int> CountSubmodulesToSync(ILocalRepositoryModel repository) |
| 108 | + { |
| 109 | + using (var repo = gitService.GetRepository(repository.LocalPath)) |
| 110 | + { |
| 111 | + var count = 0; |
| 112 | + foreach (var submodule in repo.Submodules) |
| 113 | + { |
| 114 | + var status = submodule.RetrieveStatus(); |
| 115 | + if ((status & SubmoduleStatus.WorkDirAdded) != 0) |
| 116 | + { |
| 117 | + count++; |
| 118 | + } |
| 119 | + else if ((status & SubmoduleStatus.WorkDirDeleted) != 0) |
| 120 | + { |
| 121 | + count++; |
| 122 | + } |
| 123 | + else if ((status & SubmoduleStatus.WorkDirModified) != 0) |
| 124 | + { |
| 125 | + count++; |
| 126 | + } |
| 127 | + else if ((status & SubmoduleStatus.WorkDirUninitialized) != 0) |
| 128 | + { |
| 129 | + count++; |
| 130 | + } |
| 131 | + } |
| 132 | + |
| 133 | + return Observable.Return(count); |
| 134 | + } |
| 135 | + } |
| 136 | + |
106 | 137 | public IObservable<bool> IsWorkingDirectoryClean(ILocalRepositoryModel repository) |
107 | 138 | { |
108 | 139 | // The `using` appears to resolve this issue: |
109 | 140 | // https://github.com/github/VisualStudio/issues/1306 |
110 | 141 | using (var repo = gitService.GetRepository(repository.LocalPath)) |
111 | 142 | { |
112 | | - var isClean = !IsFilthy(repo.RetrieveStatus()); |
| 143 | + var statusOptions = new StatusOptions { ExcludeSubmodules = true }; |
| 144 | + var isClean = !IsFilthy(repo.RetrieveStatus(statusOptions)); |
113 | 145 | return Observable.Return(isClean); |
114 | 146 | } |
115 | 147 | } |
@@ -154,6 +186,69 @@ public IObservable<Unit> Push(ILocalRepositoryModel repository) |
154 | 186 | }); |
155 | 187 | } |
156 | 188 |
|
| 189 | + public async Task<bool> SyncSubmodules(ILocalRepositoryModel repository, Action<string> progress) |
| 190 | + { |
| 191 | + var exitCode = await Where("git"); |
| 192 | + if (exitCode != 0) |
| 193 | + { |
| 194 | + progress(App.Resources.CouldntFindGitOnPath); |
| 195 | + return false; |
| 196 | + } |
| 197 | + |
| 198 | + return await SyncSubmodules(repository.LocalPath, progress) == 0; |
| 199 | + } |
| 200 | + |
| 201 | + // LibGit2Sharp has limited submodule support so shelling out Git.exe for submodule commands. |
| 202 | + async Task<int> SyncSubmodules(string workingDir, Action<string> progress) |
| 203 | + { |
| 204 | + var cmdArguments = "/C git submodule init & git submodule sync --recursive & git submodule update --recursive"; |
| 205 | + var startInfo = new ProcessStartInfo("cmd", cmdArguments) |
| 206 | + { |
| 207 | + WorkingDirectory = workingDir, |
| 208 | + UseShellExecute = false, |
| 209 | + CreateNoWindow = true, |
| 210 | + RedirectStandardOutput = true, |
| 211 | + RedirectStandardError = true |
| 212 | + }; |
| 213 | + |
| 214 | + using (var process = Process.Start(startInfo)) |
| 215 | + { |
| 216 | + await Task.WhenAll( |
| 217 | + ReadLinesAsync(process.StandardOutput, progress), |
| 218 | + ReadLinesAsync(process.StandardError, progress), |
| 219 | + Task.Run(() => process.WaitForExit())); |
| 220 | + return process.ExitCode; |
| 221 | + } |
| 222 | + } |
| 223 | + |
| 224 | + static Task<int> Where(string fileName) |
| 225 | + { |
| 226 | + return Task.Run(() => |
| 227 | + { |
| 228 | + var cmdArguments = "/C WHERE /Q " + fileName; |
| 229 | + var startInfo = new ProcessStartInfo("cmd", cmdArguments) |
| 230 | + { |
| 231 | + UseShellExecute = false, |
| 232 | + CreateNoWindow = true |
| 233 | + }; |
| 234 | + |
| 235 | + using (var process = Process.Start(startInfo)) |
| 236 | + { |
| 237 | + process.WaitForExit(); |
| 238 | + return process.ExitCode; |
| 239 | + } |
| 240 | + }); |
| 241 | + } |
| 242 | + |
| 243 | + static async Task ReadLinesAsync(TextReader reader, Action<string> progress) |
| 244 | + { |
| 245 | + string line; |
| 246 | + while ((line = await reader.ReadLineAsync()) != null) |
| 247 | + { |
| 248 | + progress(line); |
| 249 | + } |
| 250 | + } |
| 251 | + |
157 | 252 | public IObservable<Unit> Checkout(ILocalRepositoryModel repository, IPullRequestModel pullRequest, string localBranchName) |
158 | 253 | { |
159 | 254 | return Observable.Defer(async () => |
|
0 commit comments