using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Linq; using Octokit.Internal; namespace Octokit { /// /// Searching Code/Files /// http://developer.github.com/v3/search/#search-code /// [DebuggerDisplay("{DebuggerDisplay,nq}")] public class SearchCodeRequest : BaseSearchRequest { /// /// Initializes a new instance of the class. /// /// The search term. public SearchCodeRequest(string term) : base(term) { Repos = new RepositoryCollection(); } /// /// Initializes a new instance of the class. /// /// The term. /// The owner. /// The name. public SearchCodeRequest(string term, string owner, string name) : this(term) { Ensure.ArgumentNotNullOrEmptyString(owner, "owner"); Ensure.ArgumentNotNullOrEmptyString(name, "name"); Repos.Add(owner, name); } /// /// Optional Sort field. Can only be indexed, which indicates how recently /// a file has been indexed by the GitHub search infrastructure. /// If not provided, results are sorted by best match. /// /// /// http://developer.github.com/v3/search/#search-code /// public CodeSearchSort? SortField { get; set; } public override string Sort { get { return SortField.ToParameter(); } } /// /// Qualifies which fields are searched. With this qualifier you can restrict /// the search to just the file contents, the file path, or both. /// /// /// https://help.github.com/articles/searching-code#search-in /// private IEnumerable _inQualifier; public IEnumerable In { get { return _inQualifier; } set { if (value != null && value.Any()) { _inQualifier = value.Distinct().ToList(); } } } /// /// Searches code based on the language it’s written in. /// /// /// https://help.github.com/articles/searching-code#language /// public Language? Language { get; set; } /// /// Specifies that code from forked repositories should be searched. /// Repository forks will not be searchable unless the fork has more /// stars than the parent repository. /// /// /// https://help.github.com/articles/searching-code#forks /// public bool? Forks { get; set; } /// /// Finds files that match a certain size (in bytes). /// /// /// https://help.github.com/articles/searching-code#size /// public Range Size { get; set; } /// /// Specifies the path that the resulting file must be at. /// /// /// https://help.github.com/articles/searching-code#path /// public string Path { get; set; } /// /// Matches files with a certain extension. /// /// /// https://help.github.com/articles/searching-code#extension /// public string Extension { get; set; } /// /// Matches specific file names /// /// /// https://help.github.com/articles/searching-code/#search-by-filename /// public string FileName { get; set; } /// /// Limits searches to a specific user. /// /// /// https://help.github.com/articles/searching-code#users-organizations-and-repositories /// public string User { get; set; } /// /// Limits searches to a specific repository. /// /// /// https://help.github.com/articles/searching-code#users-organizations-and-repositories /// [SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")] public RepositoryCollection Repos { get; set; } [SuppressMessage("Microsoft.Globalization", "CA1304:SpecifyCultureInfo", MessageId = "System.String.ToLower")] public override IReadOnlyList MergedQualifiers() { var parameters = new List(); if (In != null) { parameters.Add(string.Format(CultureInfo.InvariantCulture, "in:{0}", string.Join(",", In.Select(i => i.ToParameter())))); } if (Language != null) { parameters.Add(string.Format(CultureInfo.InvariantCulture, "language:{0}", Language.ToParameter())); } if (Forks != null) { // API is expecting 'true', bool.ToString() returns 'True', if there is a better way, // please, oh please let me know... parameters.Add(string.Format(CultureInfo.InvariantCulture, "fork:{0}", Forks.Value.ToString().ToLower())); } if (Size != null) { parameters.Add(string.Format(CultureInfo.InvariantCulture, "size:{0}", Size)); } if (Path.IsNotBlank()) { parameters.Add(string.Format(CultureInfo.InvariantCulture, "path:{0}", Path)); } if (Extension.IsNotBlank()) { parameters.Add(string.Format(CultureInfo.InvariantCulture, "extension:{0}", Extension)); } if (FileName.IsNotBlank()) { parameters.Add(string.Format(CultureInfo.InvariantCulture, "filename:{0}", FileName)); } if (User.IsNotBlank()) { parameters.Add(string.Format(CultureInfo.InvariantCulture, "user:{0}", User)); } if (Repos.Any()) { var invalidFormatRepos = Repos.Where(x => !x.IsNameWithOwnerFormat()); if (invalidFormatRepos.Any()) { throw new RepositoryFormatException(invalidFormatRepos); } parameters.Add( string.Join("+", Repos.Select(x => "repo:" + x))); } return new ReadOnlyCollection(parameters); } internal string DebuggerDisplay { get { return string.Format(CultureInfo.InvariantCulture, "Term: {0} Sort: {1}", Term, Sort); } } } public enum CodeSearchSort { [Parameter(Value = "indexed")] Indexed } public enum CodeInQualifier { [Parameter(Value = "file")] File, [Parameter(Value = "path")] Path } }