/// <summary> /// Search for and download the specified gitignore, fails if not found /// </summary> /// <param name="ignore"></param> /// <returns>The downloaded .gitignore contents as a string</returns> /// <exception cref="FileNotFoundException">File was not found in the repository</exception> /// <Example> /// Input: "Visual Studio Code" -- Downloads visualstudiocode.gitignore and returns contents /// </Example> public string download(string ignore) { if (cache.Data.ContainsKey(ignore)) { if (flags.HasFlag(Options.Verbose)) { Console.WriteLine($"Downloading .gitignore for {ignore}"); } return(WebFetch.fetch(cache.Data[ignore])); } else { Console.WriteLine($"Exact match to {ignore} not found. "); IList <String> searchResults = search(ignore); if (searchResults.Count > 1) { int choice = UserInputReader.EnumerateChoices( $"There are {searchResults.Count} .gitignore files similar to your choice.", "Enter a selection:", searchResults ); if (choice > -1) { // In the case that search adds extra lines for information, clean it up string choiceName = new StringReader(searchResults[choice]).ReadLine(); if (flags.HasFlag(Options.Verbose)) { Console.WriteLine($"Downloading .gitignore for {choiceName}"); } return(WebFetch.fetch(cache.Data[choiceName])); } } else if (searchResults.Count == 1) { if (UserInputReader.GetConfirmation($".gitignore {ignore} not found. Did you mean {searchResults[0]}?", false)) { string choiceName = new StringReader(searchResults[0]).ReadLine(); if (flags.HasFlag(Options.Verbose)) { Console.WriteLine($"Downloading .gitignore for {choiceName}"); } return(WebFetch.fetch(cache.Data[choiceName])); } } } throw new System.IO.FileNotFoundException("Specified .gitignore was not found in the Repository."); }
/// <summary> /// Call before using the cache dictionary to ensure it is up to date /// </summary> /// <returns></returns> public ListingCache getCache() { ListingCache cache; DirectoryInfo pathInfo = new DirectoryInfo(cachePath); Action <ListingCache> cacheUpdate = (c) => { // Gets the latest cache from github if (flags.HasFlag(Options.Verbose)) { Console.WriteLine("Updating cache in memory from Github..."); } c.Update( Listing.FromJson( WebFetch.fetch(apiURL) ) ); if (flags.HasFlag(Options.Verbose)) { Console.WriteLine("Cache updated!"); } }; if (File.Exists(pathInfo.FullName)) { // Load cache from file cache = JsonConvert.DeserializeObject <ListingCache>(File.ReadAllText(pathInfo.FullName)); cache.flags = flags; // Get info branch info from Github Branch master = Branch.FromJson(WebFetch.fetch(branchURL)); if (flags.HasFlag(Options.Verbose)) { Console.WriteLine($"Cache successfully loaded from {pathInfo.FullName}"); } // Get the latest commits timestamp DateTimeOffset lastCommitDate = master.Commit.Commit.Author.Date; // Check the timestamp // Could probably get by just checking the last changed time on the file instead of from cache timestamp? if (DateTimeOffset.Compare(lastCommitDate, cache.TimeStamp) <= 0) { if (flags.HasFlag(Options.Verbose)) { Console.WriteLine($"Cache is outdated."); } cacheUpdate(cache); saveCache(pathInfo.FullName, cache); } else if (flags.HasFlag(Options.Verbose)) { Console.WriteLine($"Cache up to date with Github, no updates needed."); } } else { // Cache file doesn't exist, so create it and (if we're allowed) save it // and (if we're allowed) save it to ~/.getignore.cache if (flags.HasFlag(Options.Verbose)) { Console.WriteLine($"No cache found, creating in memory..."); } cache = new ListingCache(flags); cacheUpdate(cache); saveCache(pathInfo.FullName, cache); } return(cache); }
/// <summary> /// Takes in the root listing of the gitignore, and "recursively" caches all files into a Dictionary /// </summary> /// <param name="listings"></param> public void Update(Listing[] listings) { if (flags.HasFlag(Options.Verbose)) { Console.WriteLine("Writing cache..."); } // Queue of listings to check next Queue <Listing> listingsQueue = new Queue <Listing>(listings); // Dirs to throw back into the queue when it's empty Stack <Listing> dirs = new Stack <Listing>(); String ignorePattern = @"(.*)\.gitignore"; // Note that it's not actually recurisve // I find recursion difficult to maintain/debug // Do-While because Count check at this point is redundant do { while (listingsQueue.Count > 0) { Listing list = listingsQueue.Dequeue(); if (flags.HasFlag(Options.Verbose)) { Console.WriteLine(list.Path); } if (list.Type == TypeEnum.Dir) { dirs.Push(list); } else { // Only find .gitignore files while also stripping it from the name Match match = Regex.Match(list.Name, ignorePattern); if (match.Success) { Data.Add(match.Groups[1].Value, list.DownloadUrl); if (flags.HasFlag(Options.Verbose)) { Console.WriteLine($"Added {match.Groups[1].Value}."); } } } } while (dirs.Count > 0) { // Fetch contents from dir if (flags.HasFlag(Options.Verbose)) { Console.WriteLine($"Expanding directory {dirs.Peek().Name}."); } string dirJSON = WebFetch.fetch(dirs.Pop().Url); listings = Listing.FromJson(dirJSON); foreach (Listing l in listings) { listingsQueue.Enqueue(l); } } } while(listingsQueue.Count > 0); }