Skip to content

Commit a1720ed

Browse files
committed
optimize git clone by reusing existing copies of the same repo
1 parent 9a1b68a commit a1720ed

7 files changed

Lines changed: 357 additions & 47 deletions

File tree

github.v

Lines changed: 41 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -80,23 +80,56 @@ fn parse_github_timestamp(s string) int {
8080

8181
fn parse_github_owner_repo(clone_url string) ?(string, string) {
8282
mut s := clone_url.trim_space()
83+
mut lower := s.to_lower()
84+
if lower.starts_with('ssh://') {
85+
s = s['ssh://'.len..]
86+
lower = s.to_lower()
87+
}
8388
for prefix in ['https://', 'http://', 'git@'] {
84-
if s.starts_with(prefix) {
89+
if lower.starts_with(prefix) {
8590
s = s[prefix.len..]
91+
lower = s.to_lower()
8692
break
8793
}
8894
}
89-
s = s.trim_string_left('github.com')
95+
if lower.starts_with('git@') {
96+
s = s['git@'.len..]
97+
lower = s.to_lower()
98+
}
99+
if lower.starts_with('www.') {
100+
s = s['www.'.len..]
101+
lower = s.to_lower()
102+
}
103+
if !lower.starts_with('github.com') {
104+
return none
105+
}
106+
s = s['github.com'.len..]
107+
if s == '' || !(s[0] == `/` || s[0] == `:`) {
108+
return none
109+
}
90110
s = s.trim_left(':/')
91-
s = s.trim_string_right('.git')
111+
if idx := s.index('?') {
112+
s = s[..idx]
113+
}
114+
if idx := s.index('#') {
115+
s = s[..idx]
116+
}
92117
s = s.trim('/')
118+
if s.ends_with('.git') {
119+
s = s[..s.len - '.git'.len]
120+
}
93121
parts := s.split('/')
94122
if parts.len < 2 || parts[0] == '' || parts[1] == '' {
95123
return none
96124
}
97125
return parts[0], parts[1]
98126
}
99127

128+
fn is_github_clone_url(clone_url string) bool {
129+
parse_github_owner_repo(clone_url) or { return false }
130+
return true
131+
}
132+
100133
// Returns the local user id for a GitHub login, creating an unregistered
101134
// "shadow" user (no password, no email, just the username and GitHub avatar)
102135
// when one does not yet exist.
@@ -303,6 +336,11 @@ fn (mut app App) find_or_create_github_shadow_contributor(github_login string, a
303336

304337
fn (mut app App) import_github_issues(repo_id int, clone_url string, owner_user_id int) ! {
305338
eprintln('[github-import] starting for repo_id=${repo_id} clone_url=${clone_url} owner_user_id=${owner_user_id}')
339+
defer {
340+
app.sync_repo_open_issue_count(repo_id) or {
341+
eprintln('[github-import] cannot sync issue count: ${err}')
342+
}
343+
}
306344
owner, name := parse_github_owner_repo(clone_url) or {
307345
eprintln('[github-import] ERROR: cannot parse github url: ${clone_url}')
308346
return error('cannot parse github url: ${clone_url}')

gitly.v

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -437,10 +437,17 @@ fn (mut app App) migrate_tables() ! {
437437
app.add_missing_column('Repo', 'disable_milestones', db_bool_column_type())!
438438
app.add_missing_column('Repo', 'disable_wiki', db_bool_column_type())!
439439
app.add_missing_column('Repo', 'is_pinned', db_bool_column_type())!
440+
app.add_missing_column('Repo', 'created_at', 'INTEGER NOT NULL DEFAULT 0')!
441+
app.backfill_repo_created_at()!
440442

441443
app.db.exec('create index if not exists idx_commit_repo_created on ${sql_table('Commit')} (repo_id, created_at desc)')!
442444
}
443445

446+
fn (mut app App) backfill_repo_created_at() ! {
447+
created_at := int(time.now().unix())
448+
app.db.exec('update ${sql_table('Repo')} set ${sql_table('created_at')} = ${created_at} where ${sql_table('created_at')} is null or ${sql_table('created_at')} <= 0')!
449+
}
450+
444451
fn (mut app App) add_missing_column(table_name string, column_name string, column_type string) ! {
445452
if db_column_exists(mut app.db, table_name, column_name)! {
446453
return

issue.v

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -131,16 +131,32 @@ fn (mut app App) find_issue_by_id(issue_id int) ?Issue {
131131
fn (mut app App) find_repo_issues_as_page(repo_id int, page int) []Issue {
132132
off := page * commits_per_page
133133
return sql app.db {
134-
select from Issue where repo_id == repo_id && is_pr == false limit 35 offset off
134+
select from Issue where repo_id == repo_id && is_pr == false order by created_at desc limit commits_per_page offset off
135135
} or { []Issue{} }
136136
}
137137

138138
fn (mut app App) get_repo_issue_count(repo_id int) int {
139139
return sql app.db {
140-
select count from Issue where repo_id == repo_id
140+
select count from Issue where repo_id == repo_id && is_pr == false
141141
} or { 0 }
142142
}
143143

144+
fn (mut app App) sync_repo_open_issue_count(repo_id int) ! {
145+
open_issues_count := app.get_repo_issue_count(repo_id)
146+
sql app.db {
147+
update Repo set nr_open_issues = open_issues_count where id == repo_id
148+
}!
149+
}
150+
151+
fn placeholder_user(user_id int) User {
152+
username := if user_id > 0 { 'user-${user_id}' } else { 'unknown-user' }
153+
return User{
154+
id: user_id
155+
username: username
156+
avatar: default_avatar_name
157+
}
158+
}
159+
144160
fn (mut app App) find_user_issues(user_id int) []Issue {
145161
return sql app.db {
146162
select from Issue where author_id == user_id && is_pr == false order by created_at desc

issue_routes.v

Lines changed: 35 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,11 @@ pub fn (mut app App) handle_add_repo_issue(mut ctx Context, username string, rep
5858
return ctx.redirect('/${username}/${repo_name}/issues/new')
5959
}
6060
app.increment_user_post(mut ctx.user) or { app.info(err.str()) }
61-
app.add_issue(repo.id, ctx.user.id, title, text) or { app.info(err.str()) }
62-
app.increment_repo_issues(repo.id) or { app.info(err.str()) }
61+
app.add_issue(repo.id, ctx.user.id, title, text) or {
62+
app.info(err.str())
63+
return ctx.redirect('/${username}/${repo_name}/issues/new')
64+
}
65+
app.sync_repo_open_issue_count(repo.id) or { app.info(err.str()) }
6366
app.dispatch_webhook(repo.id, 'issue', WebhookIssuePayload{
6467
action: 'opened'
6568
repo: '${username}/${repo_name}'
@@ -80,16 +83,33 @@ pub fn (mut app App) handle_get_repo_issues(mut ctx Context, username string, re
8083

8184
@['/:username/:repo_name/issues/:page']
8285
pub fn (mut app App) issues(mut ctx Context, username string, repo_name string, page string) veb.Result {
83-
repo := app.find_repo_by_name_and_username(repo_name, username) or { return ctx.not_found() }
84-
page_i := page.int()
86+
mut repo := app.find_repo_by_name_and_username(repo_name, username) or {
87+
return ctx.not_found()
88+
}
89+
mut page_i := page.int()
90+
if page_i < 0 {
91+
page_i = 0
92+
}
93+
issue_count := app.get_repo_issue_count(repo.id)
94+
if repo.nr_open_issues != issue_count {
95+
app.sync_repo_open_issue_count(repo.id) or { app.info(err.str()) }
96+
repo.nr_open_issues = issue_count
97+
}
98+
page_count := calculate_pages(issue_count, commits_per_page)
99+
if page_i > page_count {
100+
if page_count == 0 {
101+
return ctx.redirect('/${repo.user_name}/${repo.name}/issues')
102+
}
103+
return ctx.redirect('/${repo.user_name}/${repo.name}/issues/${page_count}')
104+
}
85105
mut issues_with_users := []IssueWithUser{}
86106
mut issue := Issue{}
87107
mut user := User{}
88108
repo_issues := app.find_repo_issues_as_page(repo.id, page_i)
89109
mut i := 0
90110
for i = 0; i < repo_issues.len; i++ {
91111
issue = repo_issues[i]
92-
user = app.get_user_by_id(issue.author_id) or { continue }
112+
user = app.get_user_by_id(issue.author_id) or { placeholder_user(issue.author_id) }
93113
issue.labels = app.get_issue_labels(issue.id)
94114
issue.repo_author = repo.user_name
95115
issue.repo_name = repo.name
@@ -99,23 +119,8 @@ pub fn (mut app App) issues(mut ctx Context, username string, repo_name string,
99119
}
100120
}
101121
show_repo_link := false
102-
mut first := false
103-
mut last := false
104-
if repo.nr_open_issues > commits_per_page {
105-
offset := page_i * commits_per_page
106-
delta := repo.nr_open_issues - offset
107-
if delta > 0 {
108-
if delta == repo.nr_open_issues && page_i == 0 {
109-
first = true
110-
} else {
111-
last = true
112-
}
113-
}
114-
} else {
115-
last = true
116-
first = true
117-
}
118-
page_count := calculate_pages(repo.nr_open_issues, commits_per_page)
122+
first := page_i == 0
123+
last := page_i >= page_count
119124
prev_page, next_page := generate_prev_next_pages(page_i)
120125
ctx.set_page_title(['Issues', '${repo.user_name}/${repo.name}'])
121126
return $veb.html()
@@ -125,7 +130,10 @@ pub fn (mut app App) issues(mut ctx Context, username string, repo_name string,
125130
pub fn (mut app App) issue(mut ctx Context, username string, repo_name string, id string) veb.Result {
126131
repo := app.find_repo_by_name_and_username(repo_name, username) or { return ctx.not_found() }
127132
issue := app.find_issue_by_id(id.int()) or { return ctx.not_found() }
128-
issue_author := app.get_user_by_id(issue.author_id) or { return ctx.not_found() }
133+
if issue.repo_id != repo.id || issue.is_pr {
134+
return ctx.not_found()
135+
}
136+
issue_author := app.get_user_by_id(issue.author_id) or { placeholder_user(issue.author_id) }
129137
ctx.set_page_title(['${issue.title} #${issue.id}', '${repo.user_name}/${repo.name}'])
130138
mut comments_with_users := []CommentWithUser{}
131139
mut comment := Comment{}
@@ -134,7 +142,9 @@ pub fn (mut app App) issue(mut ctx Context, username string, repo_name string, i
134142
mut i := 0
135143
for i = 0; i < issue_comments.len; i++ {
136144
comment = issue_comments[i]
137-
comment_author = app.get_user_by_id(comment.author_id) or { continue }
145+
comment_author = app.get_user_by_id(comment.author_id) or {
146+
placeholder_user(comment.author_id)
147+
}
138148
comments_with_users << CommentWithUser{
139149
item: comment
140150
user: comment_author
@@ -176,7 +186,7 @@ pub fn (mut app App) user_issues(mut ctx Context, username string, tab string) v
176186
}
177187
mut issues_with_users := []IssueWithUser{}
178188
for issue in issues {
179-
issue_author := app.get_user_by_id(issue.author_id) or { continue }
189+
issue_author := app.get_user_by_id(issue.author_id) or { placeholder_user(issue.author_id) }
180190
issues_with_users << IssueWithUser{
181191
item: issue
182192
user: issue_author

0 commit comments

Comments
 (0)