public void SaveRenamedRepo(string oldOwner, string oldName, GitHubRepo newRepo) { string renameFile = Path.Combine(GetRepoFolder(oldOwner, oldName), "rename.txt"); Directory.CreateDirectory(Path.GetDirectoryName(renameFile)); File.WriteAllText(renameFile, newRepo.ToString()); }
IEnumerable <GitHubRepo> ReadRepos() { foreach (var line in File.ReadLines(_repoListFile)) { var repo = GitHubRepo.Parse(line); yield return(repo); } }
public static GitHubRepo Parse(string line) { var fields = line.Split('\t'); var ret = new GitHubRepo(); ret.ID = fields[0]; ret.Owner = fields[1]; ret.Name = fields[2]; ret.Language = fields[3]; ret.Stars = int.Parse(fields[4]); return(ret); }
// Returns true if the repo has been renamed public GitHubRepo GetRenamedRepo(GitHubRepo repo) { string renameFile = Path.Combine(GetRepoFolder(repo.Owner, repo.Name), "rename.txt"); if (File.Exists(renameFile)) { var line = File.ReadAllLines(renameFile).First(); var ret = GitHubRepo.Parse(line); if (ret.Owner == repo.Owner && ret.Name == repo.Name) { throw new InvalidDataException($"Repo {ret.Owner}/{ret.Name} redirects to itself"); } return(ret); } else { return(null); } }
async Task <IEnumerable <SearchResult> > SearchRepoAsync(GitHubRepo repo, bool handleRenamedRepos = true) { object operation = null; try { List <SearchResult> ret = new List <SearchResult>(); if (_storage.IsNotFound(repo.Owner, repo.Name)) { _logger.Verbose("{Repo} previously not found, skipping", repo.Owner + "/" + repo.Name); return(Enumerable.Empty <SearchResult>()); } if (_storage.HasRepoResults(repo.Owner, repo.Name)) { _logger.Verbose("{Repo} already downloaded", repo.Owner + "/" + repo.Name); ret = _storage.GetRepoResults(repo.Owner, repo.Name).ToList(); } else { var request = new SearchCodeRequest() { FileName = "project.json", }; request.Repos.Add(repo.Owner, repo.Name); int totalResultsReturned = 0; while (true) { if (_cancelToken.IsCancellationRequested) { return(Enumerable.Empty <SearchResult>()); } operation = new { Operation = "Search", Repo = repo.Owner + "/" + repo.Name, Page = request.Page }; SearchCodeResult result; ApiValidationException validationException = null; ExceptionDispatchInfo validationExceptionDispatchInfo = null; result = await _searchThrottler.RunAsync <SearchCodeResult>( async() => { // Do a try/catch inside here so that renamed repos don't get logged as failures by the throttler try { return(await _client.Search.SearchCode(request)); } catch (ApiValidationException ex) when(handleRenamedRepos) { validationException = ex; validationExceptionDispatchInfo = ExceptionDispatchInfo.Capture(ex); return(null); } }, operation ); if (result == null && validationException != null) { _logger.Debug(validationException, "Api validation exception for {Operation}, checking for renamed repo", operation); var renameOperation = new { Operation = "RenameCheck", Repo = repo.Owner + "/" + repo.Name }; var potentiallyRenamedRepo = await _throttler.RunAsync <Repository>( async() => { try { return(await _client.Repository.Get(repo.Owner, repo.Name)); } catch (NotFoundException) { return(null); } }, renameOperation ); if (potentiallyRenamedRepo == null) { _logger.Information("Repo {Repo} not found", renameOperation.Repo); _storage.SaveNotFound(repo.Owner, repo.Name, true); return(Enumerable.Empty <SearchResult>()); } if (potentiallyRenamedRepo.Owner.Login == repo.Owner && potentiallyRenamedRepo.Name == repo.Name) { _logger.Error("Repo was not renamed, Api validation must have failed for some other reason for {Operation}", operation); validationExceptionDispatchInfo.Throw(); } var newRepo = repo.Clone(); newRepo.Owner = potentiallyRenamedRepo.Owner.Login; newRepo.Name = potentiallyRenamedRepo.Name; _logger.Information("Repo {OldRepo} has been renamed to {Repo}", renameOperation.Repo, newRepo.Owner + "/" + newRepo.Name); _storage.SaveRenamedRepo(repo.Owner, repo.Name, newRepo); return(await SearchRepoAsync(newRepo, false)); } foreach (var item in result.Items) { string destFile = _storage.GetFilePath(repo.Owner, repo.Name, item.Path); if (Path.GetFileName(destFile).Equals("project.json", StringComparison.OrdinalIgnoreCase)) { ret.Add(new SearchResult(item)); } else { _logger.Information("{Path} was not a project.json file in {Repo}, ignoring", item.Path, repo.Owner + "/" + repo.Name); } } if (result.IncompleteResults) { _logger.Error("Incomplete search results for {Repo}", repo.Owner + "/" + repo.Name); break; } totalResultsReturned += result.Items.Count; if (totalResultsReturned >= result.TotalCount) { break; } else { request.Page += 1; } } _storage.RecordRepoResults(repo.Owner, repo.Name, ret); _logger.Information("Completed searching repo {Repo}", repo.Owner + "/" + repo.Name); } return(ret); } catch (Exception ex) { _logger.Error(ex, "{Operation} failed", operation); return(Enumerable.Empty <SearchResult>()); } }
void RecordRepoCompleted(GitHubRepo repo, IEnumerable <SearchResult> results) { _storage.RecordRepoResults(repo.Owner, repo.Name, results); _logger.Information("Completed repo {Repo}", repo.Owner + "/" + repo.Name); }