From 8f85f5a3674b77c27fef73cba1b5acffe36510cf Mon Sep 17 00:00:00 2001 From: Jiri Date: Tue, 14 Mar 2023 13:23:25 +0100 Subject: [PATCH] Search now have history --- .../nested_view/NestedViewsSearch.java | 15 ++- .../nested_view/search/BuildDetails.java | 6 +- .../nested_view/search/ExtendedSearch.java | 2 - .../nested_view/search/HistoryItem.java | 119 ++++++++++++++++++ .../search/NestedViewsSearchResult.java | 1 - .../{ => search}/ProjectWrapper.java | 6 +- .../NestedViewsSearch/search-results.jelly | 13 ++ 7 files changed, 152 insertions(+), 10 deletions(-) create mode 100644 src/main/java/hudson/plugins/nested_view/search/HistoryItem.java rename src/main/java/hudson/plugins/nested_view/{ => search}/ProjectWrapper.java (96%) diff --git a/src/main/java/hudson/plugins/nested_view/NestedViewsSearch.java b/src/main/java/hudson/plugins/nested_view/NestedViewsSearch.java index f3c2ec7..84253e7 100644 --- a/src/main/java/hudson/plugins/nested_view/NestedViewsSearch.java +++ b/src/main/java/hudson/plugins/nested_view/NestedViewsSearch.java @@ -5,6 +5,7 @@ import hudson.model.TopLevelItem; import hudson.model.View; import hudson.plugins.nested_view.search.HelpItem; +import hudson.plugins.nested_view.search.HistoryItem; import hudson.plugins.nested_view.search.NamableWithClass; import hudson.plugins.nested_view.search.NestedViewsSearchResult; import hudson.plugins.nested_view.search.Query; @@ -34,7 +35,7 @@ public class NestedViewsSearch extends Search { private static final long refreshTimeout = 10l * 60l * 1000l; private static final int refreshAmount = 20; - private final static Logger LOGGER = Logger.getLogger(Search.class.getName()); + public final static Logger LOGGER = Logger.getLogger(Search.class.getName()); private static transient volatile List allCache = new ArrayList(0); private static transient volatile int allTTL = 0; private static transient volatile Date lastRefresh = new Date(0); @@ -96,6 +97,7 @@ public void doIndex(StaplerRequest req, StaplerResponse rsp) throws IOException, } } } + putToHistory(query, hits.size(), new Date()); } Collections.sort(hits); //todo, add paging &start=&count= .. defaulting to 0 and somwhere on 1000. Probably add next/prev links to jelly. Include `showing x/form` in jelly @@ -103,6 +105,17 @@ public void doIndex(StaplerRequest req, StaplerResponse rsp) throws IOException, v.forward(req, rsp); } + @SuppressFBWarnings(value = {"ST_WRITE_TO_STATIC_FROM_INSTANCE_METHOD"}, justification = "history is shared") + private void putToHistory(String query, int size, Date date) { + HistoryItem his = new HistoryItem(query.trim().replaceAll("\\s+", " "), size, date); + HistoryItem.add(his); + } + + @SuppressFBWarnings(value = {"ST_WRITE_TO_STATIC_FROM_INSTANCE_METHOD"}, justification = "history is shared") + public List getHistory() { + return HistoryItem.get(); + } + @Override public SearchResult getSuggestions(final StaplerRequest req, @QueryParameter final String query) { SearchResult suggestedItems = super.getSuggestions(req, query); diff --git a/src/main/java/hudson/plugins/nested_view/search/BuildDetails.java b/src/main/java/hudson/plugins/nested_view/search/BuildDetails.java index b053d02..37bd16d 100644 --- a/src/main/java/hudson/plugins/nested_view/search/BuildDetails.java +++ b/src/main/java/hudson/plugins/nested_view/search/BuildDetails.java @@ -48,9 +48,13 @@ public LinkableCandidate toLinkable(String projectName) { } post = post + "/" + result + "/" + timeStampString + " ago"; ; - return new LinkableCandidate(pre, link, post, Jenkins.get().getRootUrl().replaceAll("[\\/]+$", "") + "/job/" + projectName + "/" + id); + return new LinkableCandidate(pre, link, post, getJenkinsUrl() + "/job/" + projectName + "/" + id); } else { return new LinkableCandidate(prefix + "n/a"); } } + + public static String getJenkinsUrl() { + return Jenkins.get().getRootUrl().replaceAll("[\\/]+$", ""); + } } diff --git a/src/main/java/hudson/plugins/nested_view/search/ExtendedSearch.java b/src/main/java/hudson/plugins/nested_view/search/ExtendedSearch.java index 2256227..d73315f 100644 --- a/src/main/java/hudson/plugins/nested_view/search/ExtendedSearch.java +++ b/src/main/java/hudson/plugins/nested_view/search/ExtendedSearch.java @@ -1,7 +1,5 @@ package hudson.plugins.nested_view.search; -import hudson.plugins.nested_view.ProjectWrapper; - // for some reasons, if class implements some interfaces, only methods from interface are available form jelly! // thus this artificial interface... public interface ExtendedSearch { diff --git a/src/main/java/hudson/plugins/nested_view/search/HistoryItem.java b/src/main/java/hudson/plugins/nested_view/search/HistoryItem.java new file mode 100644 index 0000000..ab7b912 --- /dev/null +++ b/src/main/java/hudson/plugins/nested_view/search/HistoryItem.java @@ -0,0 +1,119 @@ +package hudson.plugins.nested_view.search; + +import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; +import hudson.plugins.nested_view.NestedViewsSearch; +import jenkins.model.Jenkins; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Date; +import java.util.List; +import java.util.logging.Level; +import java.util.stream.Collectors; + +public class HistoryItem { + + private static final int MAX_HISTORY = 500; + private static final File historyCache = new File(Jenkins.get().root, ".nested-view-serch.cache"); + private static final List history = HistoryItem.load(); + + private final String query; + private final int size; + private final Date date; + + @SuppressFBWarnings(value = {"EI_EXPOSE_REP2"}, justification = "date is not cared") + public HistoryItem(String query, int size, Date date) { + this.query = query; + this.size = size; + this.date = date; + } + + public static void save() { + try { + saveImp(); + } catch (Exception ex) { + NestedViewsSearch.LOGGER.log(Level.SEVERE, "saving nested view search history failed", ex); + } + } + + public static void saveImp() throws IOException { + Files.write(historyCache.toPath(), history.stream().map(a -> a.toSave()).collect(Collectors.toList())); + } + + public static List load() { + List l = new ArrayList<>(0); + if (historyCache.exists()) try { + l = Files.readAllLines(historyCache.toPath()); + } catch (Exception ex) { + NestedViewsSearch.LOGGER.log(Level.SEVERE, "loading nested view search history failed", ex); + } + ArrayList r = new ArrayList(MAX_HISTORY); + for (String s : l) { + try { + r.add(new HistoryItem(s)); + } catch (Exception ex) { + NestedViewsSearch.LOGGER.log(Level.SEVERE, "reading nested view search history " + s + " failed", ex); + } + } + return Collections.synchronizedList(r); + } + + public static List get() { + return Collections.unmodifiableList(history); + } + + public static void add(HistoryItem his) { + history.removeAll(Collections.singleton(his)); + history.add(0, his); + while (history.size() > MAX_HISTORY) { + history.remove(history.size() - 1); + } + save(); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + HistoryItem that = (HistoryItem) o; + return query.equals(that.query); + } + + @Override + public int hashCode() { + return query.hashCode(); + } + + public String getQuery() { + return query; + } + + public String getUrl() { + return BuildDetails.getJenkinsUrl() + "/search/?q=" + getQuery(); + } + + public int getSize() { + return size; + } + + public String getDate() { + return new SimpleDateFormat("HH:mm:ss dd/MM").format(date); + } + + public String toSave() { + return size + " " + date.getTime() + " " + query; + } + + public HistoryItem(String saved) { + String[] sd = saved.split(" "); + size = Integer.parseInt(sd[0]); + date = new Date(Long.parseLong(sd[1])); + query = saved.replace(size + " " + date.getTime() + " ", ""); + + } + +} diff --git a/src/main/java/hudson/plugins/nested_view/search/NestedViewsSearchResult.java b/src/main/java/hudson/plugins/nested_view/search/NestedViewsSearchResult.java index b3f12ba..3cfa854 100644 --- a/src/main/java/hudson/plugins/nested_view/search/NestedViewsSearchResult.java +++ b/src/main/java/hudson/plugins/nested_view/search/NestedViewsSearchResult.java @@ -2,7 +2,6 @@ import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import hudson.model.AbstractProject; -import hudson.plugins.nested_view.ProjectWrapper; import hudson.search.SearchIndex; import hudson.search.SearchItem; diff --git a/src/main/java/hudson/plugins/nested_view/ProjectWrapper.java b/src/main/java/hudson/plugins/nested_view/search/ProjectWrapper.java similarity index 96% rename from src/main/java/hudson/plugins/nested_view/ProjectWrapper.java rename to src/main/java/hudson/plugins/nested_view/search/ProjectWrapper.java index 07584aa..e6c5d95 100644 --- a/src/main/java/hudson/plugins/nested_view/ProjectWrapper.java +++ b/src/main/java/hudson/plugins/nested_view/search/ProjectWrapper.java @@ -1,4 +1,4 @@ -package hudson.plugins.nested_view; +package hudson.plugins.nested_view.search; import java.util.ArrayList; import java.util.Arrays; @@ -15,10 +15,6 @@ import hudson.model.AbstractProject; import hudson.model.Result; import hudson.model.Run; -import hudson.plugins.nested_view.search.BuildDetails; -import hudson.plugins.nested_view.search.LinkableCandidate; -import hudson.plugins.nested_view.search.NamableWithClass; -import hudson.plugins.nested_view.search.Query; public class ProjectWrapper { diff --git a/src/main/resources/hudson/plugins/nested_view/NestedViewsSearch/search-results.jelly b/src/main/resources/hudson/plugins/nested_view/NestedViewsSearch/search-results.jelly index 2257879..a8b4826 100644 --- a/src/main/resources/hudson/plugins/nested_view/NestedViewsSearch/search-results.jelly +++ b/src/main/resources/hudson/plugins/nested_view/NestedViewsSearch/search-results.jelly @@ -6,6 +6,19 @@

Search help

+ Search History (expand) + +

${%Supported keywords with an example}