gemstar 0.0.2 → 1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +6 -14
- data/README.md +13 -0
- data/lib/gemstar/cache.rb +47 -10
- data/lib/gemstar/cache_cli.rb +12 -0
- data/lib/gemstar/cache_warmer.rb +120 -0
- data/lib/gemstar/change_log.rb +75 -44
- data/lib/gemstar/cli.rb +12 -0
- data/lib/gemstar/commands/cache.rb +12 -0
- data/lib/gemstar/commands/diff.rb +3 -3
- data/lib/gemstar/commands/server.rb +136 -0
- data/lib/gemstar/config.rb +15 -0
- data/lib/gemstar/git_repo.rb +74 -7
- data/lib/gemstar/lock_file.rb +86 -8
- data/lib/gemstar/project.rb +245 -0
- data/lib/gemstar/request_logger.rb +31 -0
- data/lib/gemstar/ruby_gems_metadata.rb +49 -33
- data/lib/gemstar/version.rb +1 -1
- data/lib/gemstar/web/app.rb +936 -0
- data/lib/gemstar/web/templates/app.css +523 -0
- data/lib/gemstar/web/templates/app.js.erb +226 -0
- data/lib/gemstar/web/templates/page.html.erb +15 -0
- data/lib/gemstar/webrick_logger.rb +22 -0
- data/lib/gemstar.rb +6 -1
- metadata +70 -3
- data/lib/gemstar/railtie.rb +0 -6
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
(() => {
|
|
2
|
+
const projectSelect = document.querySelector("[data-project-select]");
|
|
3
|
+
const fromSelect = document.querySelector("[data-from-select]");
|
|
4
|
+
const toSelect = document.querySelector("[data-to-select]");
|
|
5
|
+
const sidebarPanel = document.querySelector("[data-sidebar-panel]");
|
|
6
|
+
const filterButtons = Array.from(document.querySelectorAll("[data-filter-button]"));
|
|
7
|
+
const gemSearch = document.querySelector("[data-gem-search]");
|
|
8
|
+
const emptyGemList = document.querySelector("[data-gem-list-empty]");
|
|
9
|
+
let detailPanel = document.querySelector("[data-detail-panel]");
|
|
10
|
+
const gemLinks = Array.from(document.querySelectorAll("[data-gem-link]"));
|
|
11
|
+
let detailPollTimer = null;
|
|
12
|
+
let currentFilter = <%= selected_filter_json %>;
|
|
13
|
+
let currentSearch = "";
|
|
14
|
+
const emptyDetailHtml = <%= empty_detail_html_json %>;
|
|
15
|
+
|
|
16
|
+
const visibleGemLinks = () => gemLinks.filter((link) => !link.hidden);
|
|
17
|
+
const currentSelectedIndex = () => visibleGemLinks().findIndex((link) => link.classList.contains("is-selected"));
|
|
18
|
+
const clearSidebarSelection = () => {
|
|
19
|
+
gemLinks.forEach((link) => {
|
|
20
|
+
link.classList.remove("is-selected");
|
|
21
|
+
});
|
|
22
|
+
};
|
|
23
|
+
const requestedGemName = () => new URL(window.location.href).searchParams.get("gem");
|
|
24
|
+
|
|
25
|
+
const applyGemFilter = (filter) => {
|
|
26
|
+
currentFilter = filter;
|
|
27
|
+
const pinnedGemName = requestedGemName();
|
|
28
|
+
const searchTerm = currentSearch.trim().toLowerCase();
|
|
29
|
+
|
|
30
|
+
filterButtons.forEach((button) => {
|
|
31
|
+
button.classList.toggle("is-active", button.dataset.filterButton === filter);
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
gemLinks.forEach((link) => {
|
|
35
|
+
const updated = link.dataset.gemUpdated === "true";
|
|
36
|
+
const pinned = pinnedGemName && link.dataset.gemName === pinnedGemName;
|
|
37
|
+
const matchesSearch = searchTerm === "" || link.dataset.gemName.toLowerCase().includes(searchTerm);
|
|
38
|
+
link.hidden = ((filter === "updated" && !updated && !pinned) || !matchesSearch);
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
if (emptyGemList) {
|
|
42
|
+
const emptyMessage = searchTerm === "" ? "No updated gems in this revision range." : "No gems match this filter.";
|
|
43
|
+
emptyGemList.hidden = visibleGemLinks().length !== 0;
|
|
44
|
+
const text = emptyGemList.querySelector("p");
|
|
45
|
+
if (text) text.textContent = emptyMessage;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
if (currentSelectedIndex() === -1) {
|
|
49
|
+
clearSidebarSelection();
|
|
50
|
+
replaceDetail(emptyDetailHtml);
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
const syncSidebarSelection = (gemName = null, keepVisible = false) => {
|
|
55
|
+
const effectiveGemName = gemName || new URL(window.location.href).searchParams.get("gem");
|
|
56
|
+
if (!effectiveGemName) {
|
|
57
|
+
clearSidebarSelection();
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
let selectedLink = null;
|
|
62
|
+
gemLinks.forEach((link) => {
|
|
63
|
+
const matches = link.dataset.gemName === effectiveGemName;
|
|
64
|
+
link.classList.toggle("is-selected", matches);
|
|
65
|
+
if (matches) {
|
|
66
|
+
selectedLink = link;
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
if (keepVisible && sidebarPanel && selectedLink) {
|
|
71
|
+
selectedLink.scrollIntoView({ block: "nearest" });
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
if ("scrollRestoration" in history) {
|
|
76
|
+
history.scrollRestoration = "manual";
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const replaceDetail = (html) => {
|
|
80
|
+
if (!detailPanel) return;
|
|
81
|
+
detailPanel.outerHTML = html;
|
|
82
|
+
detailPanel = document.querySelector("[data-detail-panel]");
|
|
83
|
+
if (detailPanel) detailPanel.scrollTop = 0;
|
|
84
|
+
scheduleDetailPoll();
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
const stopDetailPoll = () => {
|
|
88
|
+
if (detailPollTimer) {
|
|
89
|
+
clearTimeout(detailPollTimer);
|
|
90
|
+
detailPollTimer = null;
|
|
91
|
+
}
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
const fetchDetail = (url, pushHistory = true) => {
|
|
95
|
+
fetch(url, { headers: { "X-Requested-With": "gemstar-detail" } })
|
|
96
|
+
.then((response) => response.text())
|
|
97
|
+
.then((html) => {
|
|
98
|
+
replaceDetail(html);
|
|
99
|
+
if (pushHistory) {
|
|
100
|
+
const pageUrl = new URL(window.location.href);
|
|
101
|
+
const detailUrl = new URL(url, window.location.origin);
|
|
102
|
+
pageUrl.search = detailUrl.search;
|
|
103
|
+
pageUrl.searchParams.set("filter", currentFilter);
|
|
104
|
+
window.history.pushState({}, "", pageUrl);
|
|
105
|
+
}
|
|
106
|
+
const detailUrl = new URL(url, window.location.origin);
|
|
107
|
+
syncSidebarSelection(detailUrl.searchParams.get("gem"));
|
|
108
|
+
});
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
const activateGemLink = (link, pushHistory = true, keepVisible = false) => {
|
|
112
|
+
if (!link) return;
|
|
113
|
+
|
|
114
|
+
syncSidebarSelection(link.dataset.gemName, keepVisible);
|
|
115
|
+
fetchDetail(link.dataset.detailUrl || link.href, pushHistory);
|
|
116
|
+
|
|
117
|
+
if (sidebarPanel) {
|
|
118
|
+
sidebarPanel.focus({ preventScroll: true });
|
|
119
|
+
}
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
const scheduleDetailPoll = () => {
|
|
123
|
+
stopDetailPoll();
|
|
124
|
+
if (!detailPanel || detailPanel.dataset.detailPending !== "true") return;
|
|
125
|
+
detailPollTimer = setTimeout(() => {
|
|
126
|
+
fetchDetail(detailPanel.dataset.detailUrl, false);
|
|
127
|
+
}, 1000);
|
|
128
|
+
};
|
|
129
|
+
|
|
130
|
+
if (detailPanel) {
|
|
131
|
+
detailPanel.scrollTop = 0;
|
|
132
|
+
scheduleDetailPoll();
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
syncSidebarSelection(null, true);
|
|
136
|
+
applyGemFilter(currentFilter);
|
|
137
|
+
|
|
138
|
+
gemLinks.forEach((link) => {
|
|
139
|
+
link.addEventListener("click", (event) => {
|
|
140
|
+
event.preventDefault();
|
|
141
|
+
activateGemLink(link);
|
|
142
|
+
});
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
filterButtons.forEach((button) => {
|
|
146
|
+
button.addEventListener("click", () => {
|
|
147
|
+
applyGemFilter(button.dataset.filterButton);
|
|
148
|
+
if (sidebarPanel) {
|
|
149
|
+
sidebarPanel.scrollTop = 0;
|
|
150
|
+
}
|
|
151
|
+
const url = new URL(window.location.href);
|
|
152
|
+
url.searchParams.set("filter", currentFilter);
|
|
153
|
+
window.history.replaceState({}, "", url);
|
|
154
|
+
syncSidebarSelection(null, true);
|
|
155
|
+
});
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
if (gemSearch) {
|
|
159
|
+
gemSearch.addEventListener("input", (event) => {
|
|
160
|
+
currentSearch = event.target.value || "";
|
|
161
|
+
applyGemFilter(currentFilter);
|
|
162
|
+
if (sidebarPanel) {
|
|
163
|
+
sidebarPanel.scrollTop = 0;
|
|
164
|
+
}
|
|
165
|
+
syncSidebarSelection(null, true);
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
const navigate = (params) => {
|
|
170
|
+
const url = new URL(window.location.href);
|
|
171
|
+
Object.entries(params).forEach(([key, value]) => {
|
|
172
|
+
if (value === null || value === undefined || value === "") {
|
|
173
|
+
url.searchParams.delete(key);
|
|
174
|
+
} else {
|
|
175
|
+
url.searchParams.set(key, value);
|
|
176
|
+
}
|
|
177
|
+
});
|
|
178
|
+
window.location.href = url.toString();
|
|
179
|
+
};
|
|
180
|
+
|
|
181
|
+
if (projectSelect) {
|
|
182
|
+
projectSelect.addEventListener("change", (event) => {
|
|
183
|
+
if (event.target.value === "__add__") {
|
|
184
|
+
window.alert("Add project UI is next. For now, restart gemstar server with another --project path.");
|
|
185
|
+
event.target.value = "<%= selected_project_index %>";
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
navigate({ project: event.target.value, from: null, to: "worktree", filter: currentFilter, gem: null });
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
if (fromSelect) {
|
|
193
|
+
fromSelect.addEventListener("change", (event) => {
|
|
194
|
+
navigate({ from: event.target.value, filter: currentFilter, gem: null });
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
if (toSelect) {
|
|
199
|
+
toSelect.addEventListener("change", (event) => {
|
|
200
|
+
navigate({ to: event.target.value, filter: currentFilter, gem: null });
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
document.addEventListener("keydown", (event) => {
|
|
205
|
+
const tagName = document.activeElement && document.activeElement.tagName;
|
|
206
|
+
if (tagName === "INPUT" || tagName === "TEXTAREA" || tagName === "SELECT") return;
|
|
207
|
+
const links = visibleGemLinks();
|
|
208
|
+
if (!links.length) return;
|
|
209
|
+
|
|
210
|
+
const selectedGem = currentSelectedIndex();
|
|
211
|
+
const currentIndex = selectedGem >= 0 ? selectedGem : 0;
|
|
212
|
+
let nextIndex = null;
|
|
213
|
+
|
|
214
|
+
if (event.key === "ArrowDown") nextIndex = Math.min(currentIndex + 1, links.length - 1);
|
|
215
|
+
if (event.key === "ArrowUp") nextIndex = Math.max(currentIndex - 1, 0);
|
|
216
|
+
|
|
217
|
+
if (nextIndex !== null && nextIndex !== currentIndex) {
|
|
218
|
+
event.preventDefault();
|
|
219
|
+
activateGemLink(links[nextIndex], true, true);
|
|
220
|
+
}
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
window.addEventListener("popstate", () => {
|
|
224
|
+
window.location.reload();
|
|
225
|
+
});
|
|
226
|
+
})();
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
6
|
+
<title><%= title %></title>
|
|
7
|
+
<link rel="icon" href="<%= favicon_data_uri %>">
|
|
8
|
+
<style>
|
|
9
|
+
<%= styles_css %>
|
|
10
|
+
</style>
|
|
11
|
+
</head>
|
|
12
|
+
<body>
|
|
13
|
+
<%= body_html %>
|
|
14
|
+
</body>
|
|
15
|
+
</html>
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
module Gemstar
|
|
2
|
+
class WEBrickLogger < WEBrick::Log
|
|
3
|
+
EXPECTED_DISCONNECT_ERRORS = [
|
|
4
|
+
Errno::ECONNRESET,
|
|
5
|
+
Errno::ECONNABORTED,
|
|
6
|
+
Errno::EPIPE
|
|
7
|
+
].freeze
|
|
8
|
+
|
|
9
|
+
def error(message)
|
|
10
|
+
return if expected_disconnect?(message)
|
|
11
|
+
|
|
12
|
+
super
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
private
|
|
16
|
+
|
|
17
|
+
def expected_disconnect?(message)
|
|
18
|
+
EXPECTED_DISCONNECT_ERRORS.any? { |error_class| message.is_a?(error_class) } ||
|
|
19
|
+
message.to_s.start_with?("Errno::ECONNRESET:", "Errno::ECONNABORTED:", "Errno::EPIPE:")
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
data/lib/gemstar.rb
CHANGED
|
@@ -1,16 +1,21 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require "gemstar/version"
|
|
4
|
-
require "gemstar/
|
|
4
|
+
require "gemstar/cache_cli"
|
|
5
5
|
require "gemstar/cli"
|
|
6
|
+
require "gemstar/cache_warmer"
|
|
6
7
|
require "gemstar/commands/command"
|
|
8
|
+
require "gemstar/commands/cache"
|
|
7
9
|
require "gemstar/commands/diff"
|
|
10
|
+
require "gemstar/commands/server"
|
|
11
|
+
require "gemstar/config"
|
|
8
12
|
require "gemstar/outputs/basic"
|
|
9
13
|
require "gemstar/outputs/html"
|
|
10
14
|
require "gemstar/cache"
|
|
11
15
|
require "gemstar/change_log"
|
|
12
16
|
require "gemstar/git_hub"
|
|
13
17
|
require "gemstar/lock_file"
|
|
18
|
+
require "gemstar/project"
|
|
14
19
|
require "gemstar/remote_repository"
|
|
15
20
|
require "gemstar/utils"
|
|
16
21
|
require "gemstar/ruby_gems_metadata"
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: gemstar
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version:
|
|
4
|
+
version: '1.0'
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Florian Dejako
|
|
@@ -65,6 +65,20 @@ dependencies:
|
|
|
65
65
|
- - "~>"
|
|
66
66
|
- !ruby/object:Gem::Version
|
|
67
67
|
version: '5.0'
|
|
68
|
+
- !ruby/object:Gem::Dependency
|
|
69
|
+
name: rerun
|
|
70
|
+
requirement: !ruby/object:Gem::Requirement
|
|
71
|
+
requirements:
|
|
72
|
+
- - "~>"
|
|
73
|
+
- !ruby/object:Gem::Version
|
|
74
|
+
version: '0.14'
|
|
75
|
+
type: :development
|
|
76
|
+
prerelease: false
|
|
77
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
78
|
+
requirements:
|
|
79
|
+
- - "~>"
|
|
80
|
+
- !ruby/object:Gem::Version
|
|
81
|
+
version: '0.14'
|
|
68
82
|
- !ruby/object:Gem::Dependency
|
|
69
83
|
name: kramdown
|
|
70
84
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -149,6 +163,48 @@ dependencies:
|
|
|
149
163
|
- - "~>"
|
|
150
164
|
- !ruby/object:Gem::Version
|
|
151
165
|
version: '1.18'
|
|
166
|
+
- !ruby/object:Gem::Dependency
|
|
167
|
+
name: roda
|
|
168
|
+
requirement: !ruby/object:Gem::Requirement
|
|
169
|
+
requirements:
|
|
170
|
+
- - "~>"
|
|
171
|
+
- !ruby/object:Gem::Version
|
|
172
|
+
version: '3.90'
|
|
173
|
+
type: :runtime
|
|
174
|
+
prerelease: false
|
|
175
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
176
|
+
requirements:
|
|
177
|
+
- - "~>"
|
|
178
|
+
- !ruby/object:Gem::Version
|
|
179
|
+
version: '3.90'
|
|
180
|
+
- !ruby/object:Gem::Dependency
|
|
181
|
+
name: rackup
|
|
182
|
+
requirement: !ruby/object:Gem::Requirement
|
|
183
|
+
requirements:
|
|
184
|
+
- - "~>"
|
|
185
|
+
- !ruby/object:Gem::Version
|
|
186
|
+
version: '2.2'
|
|
187
|
+
type: :runtime
|
|
188
|
+
prerelease: false
|
|
189
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
190
|
+
requirements:
|
|
191
|
+
- - "~>"
|
|
192
|
+
- !ruby/object:Gem::Version
|
|
193
|
+
version: '2.2'
|
|
194
|
+
- !ruby/object:Gem::Dependency
|
|
195
|
+
name: webrick
|
|
196
|
+
requirement: !ruby/object:Gem::Requirement
|
|
197
|
+
requirements:
|
|
198
|
+
- - "~>"
|
|
199
|
+
- !ruby/object:Gem::Version
|
|
200
|
+
version: '1.9'
|
|
201
|
+
type: :runtime
|
|
202
|
+
prerelease: false
|
|
203
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
204
|
+
requirements:
|
|
205
|
+
- - "~>"
|
|
206
|
+
- !ruby/object:Gem::Version
|
|
207
|
+
version: '1.9'
|
|
152
208
|
description: Gem changelog viewer and more, but starting as a changelog viewer for
|
|
153
209
|
bundled gems.
|
|
154
210
|
email:
|
|
@@ -164,20 +220,31 @@ files:
|
|
|
164
220
|
- bin/gemstar
|
|
165
221
|
- lib/gemstar.rb
|
|
166
222
|
- lib/gemstar/cache.rb
|
|
223
|
+
- lib/gemstar/cache_cli.rb
|
|
224
|
+
- lib/gemstar/cache_warmer.rb
|
|
167
225
|
- lib/gemstar/change_log.rb
|
|
168
226
|
- lib/gemstar/cli.rb
|
|
227
|
+
- lib/gemstar/commands/cache.rb
|
|
169
228
|
- lib/gemstar/commands/command.rb
|
|
170
229
|
- lib/gemstar/commands/diff.rb
|
|
230
|
+
- lib/gemstar/commands/server.rb
|
|
231
|
+
- lib/gemstar/config.rb
|
|
171
232
|
- lib/gemstar/git_hub.rb
|
|
172
233
|
- lib/gemstar/git_repo.rb
|
|
173
234
|
- lib/gemstar/lock_file.rb
|
|
174
235
|
- lib/gemstar/outputs/basic.rb
|
|
175
236
|
- lib/gemstar/outputs/html.rb
|
|
176
|
-
- lib/gemstar/
|
|
237
|
+
- lib/gemstar/project.rb
|
|
177
238
|
- lib/gemstar/remote_repository.rb
|
|
239
|
+
- lib/gemstar/request_logger.rb
|
|
178
240
|
- lib/gemstar/ruby_gems_metadata.rb
|
|
179
241
|
- lib/gemstar/utils.rb
|
|
180
242
|
- lib/gemstar/version.rb
|
|
243
|
+
- lib/gemstar/web/app.rb
|
|
244
|
+
- lib/gemstar/web/templates/app.css
|
|
245
|
+
- lib/gemstar/web/templates/app.js.erb
|
|
246
|
+
- lib/gemstar/web/templates/page.html.erb
|
|
247
|
+
- lib/gemstar/webrick_logger.rb
|
|
181
248
|
homepage: https://github.com/FDj/gemstar
|
|
182
249
|
licenses:
|
|
183
250
|
- MIT
|
|
@@ -199,7 +266,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
199
266
|
- !ruby/object:Gem::Version
|
|
200
267
|
version: '0'
|
|
201
268
|
requirements: []
|
|
202
|
-
rubygems_version: 3.
|
|
269
|
+
rubygems_version: 3.6.9
|
|
203
270
|
specification_version: 4
|
|
204
271
|
summary: Making sense of gems.
|
|
205
272
|
test_files: []
|