A src/git/branches.rs +35 -0
@@ 0,0 1,35 @@
+use crate::config::CONFIG;
+use crate::git::commits::{Commits, get_commits};
+use serde_derive::Serialize;
+
+pub fn branches(repo_name: String) -> Option<Vec<Branch>> {
+ let mut repo_path = CONFIG.git_location.clone();
+ repo_path.push(format!("{}.git", repo_name));
+ let repo = git2::Repository::open(repo_path).ok()?;
+ let mut branches = Vec::new();
+ for i in repo.branches(Some(git2::BranchType::Local)).ok()? {
+ match i {
+ Ok(x) => match x.0.name() {
+ Ok(name) => match name {
+ Some(name) => branches.push(Branch {
+ branch: name.to_string(),
+ commit: match get_commits(repo_name.clone(), 1, Some(name.to_string()), None) {
+ Some(x) => x.first().cloned(),
+ None => None
+ },
+ }),
+ None => {}
+ }
+ Err(_) => {}
+ },
+ Err(_) => {}
+ }
+ }
+ Some(branches)
+}
+
+#[derive(Serialize, Clone)]
+pub struct Branch {
+ branch: String,
+ commit: Option<Commits>
+}
M src/git/commits.rs => src/git/commits.rs +24 -1
@@ 17,7 17,30 @@ pub fn get_commits(
revwalk.set_sorting(git2::Sort::TIME).ok()?;
match after {
- Some(id) => revwalk.push(git2::Oid::from_str(id.as_str()).ok()?).ok()?,
+ Some(id) => match git2::Oid::from_str(id.as_str()) {
+ Ok(x) => revwalk.push(x).ok()?,
+ Err(_) => {
+ let oid = match repo.find_branch(&id, git2::BranchType::Local) {
+ Ok(x) => x.get().target(),
+ Err(_) => {
+ let mut tag = None;
+ let tag_name = id.as_bytes();
+ repo.tag_foreach(|x,y| {
+ if &y[10..] == tag_name {
+ tag = Some(x);
+ return false;
+ }
+ true
+ });
+ tag
+ }
+ };
+ match oid {
+ Some(x) => revwalk.push(x).ok()?,
+ None => revwalk.push_head().ok()?
+ }
+ }
+ }
None => revwalk.push_head().ok()?,
}
let mut commits = Vec::new();
M src/git/mod.rs => src/git/mod.rs +1 -0
@@ 5,3 5,4 @@ pub mod file;
pub mod main_branch;
pub mod repos;
pub mod tag;
+pub mod branches;
M src/git/tag.rs => src/git/tag.rs +39 -11
@@ 1,18 1,46 @@
use crate::config::CONFIG;
+use crate::git::commits::{get_commits, Commits};
+use serde_derive::Serialize;
-pub fn get_tag(repo_name: String, amount: usize) -> Option<Vec<String>> {
+pub fn get_tag(repo_name: String, amount: usize, after: usize, name: Option<String>) -> Option<(Vec<Tags>, usize)> {
let mut repo_path = CONFIG.git_location.clone();
repo_path.push(format!("{}.git", repo_name));
let repo = git2::Repository::open(repo_path).ok()?;
let mut tags = Vec::new();
- let mut i = 0;
- let repo_tags = repo.tag_names(None).ok()?;
- let mut tags_stringarray = repo_tags.iter().rev();
- let mut tag = tags_stringarray.next();
- while i < amount && tag.is_some() && tag.unwrap().is_some() {
- tags.push(tag.unwrap().unwrap().to_string());
- tag = tags_stringarray.next();
- i += 1;
- }
- Some(tags)
+ let total = repo.tag_names(None).ok()?.len();
+ let mut i = total-1;
+ repo.tag_foreach(|x,y| {
+ if (name.is_some() && name.as_ref().unwrap().as_bytes() == &y[10..]) || name.is_none() {
+ if i >= after && (total < amount + after || i < amount - after) {
+ match get_commits(repo_name.clone(), 1, Some(x.to_string()), None) {
+ Some(z) => match z.first() {
+ Some(z) => tags.push(Tags {
+ commit: z.clone(),
+ body: match repo.find_tag(x) {
+ Ok(x) => x.message().unwrap_or("").to_string(),
+ Err(_) => "".to_string()
+ },
+ name: std::str::from_utf8(&y[10..]).unwrap_or("").to_string()
+ }),
+ None => {}
+ },
+ None => {}
+ }
+ }
+ if i < after+1 {
+ return false;
+ }
+ i-=1;
+ }
+ true
+ });
+ tags.reverse();
+ Some((tags, total))
+}
+
+#[derive(Serialize, Clone)]
+pub struct Tags {
+ commit: Commits,
+ name: String,
+ body: String,
}
M src/main.rs => src/main.rs +4 -1
@@ 17,6 17,7 @@ use crate::repository::log;
use crate::repository::raw;
use crate::repository::summary;
use crate::repository::tree;
+use crate::repository::refs;
use crate::utils::own_pathbuf::PathBufWithDotfiles;
use rocket_dyn_templates::Template;
@@ 38,7 39,9 @@ fn rocket() -> _ {
log::log,
blame::blames,
commit::commit,
- commit::patch
+ commit::patch,
+ refs::refs,
+ refs::refs_id
],
)
.attach(Template::fairing())
M src/repository/blame.rs => src/repository/blame.rs +1 -1
@@ 51,7 51,7 @@ pub fn blames(repo: String, branch: String, location: PathBufWithDotfiles) -> Op
config: repo_config(repo.clone()),
domain: CONFIG.domain.to_string(),
active: "tree",
- commit: match get_commits(repo.clone(), 1, None, Some(format!("{}", location.get().display()).replace("//", "/"))) {
+ commit: match get_commits(repo.clone(), 1, Some(branch.clone()), Some(format!("{}", location.get().display()).replace("//", "/"))) {
Some(x) => match x.clone().get(0) {
Some(x) => Some(x.clone()),
None => None
M src/repository/log.rs => src/repository/log.rs +1 -1
@@ 58,7 58,7 @@ pub fn log(
let commits = get_commits(
repo.clone(),
21,
- from,
+ Some(from.unwrap_or(branch.clone())),
Some(format!("{}", location.get().display()).replace("//", "/")),
);
let last_commit = match commits {
M src/repository/mod.rs => src/repository/mod.rs +1 -0
@@ 4,3 4,4 @@ pub mod log;
pub mod raw;
pub mod summary;
pub mod tree;
+pub mod refs;
A src/repository/refs.rs +65 -0
@@ 0,0 1,65 @@
+use crate::config::CONFIG;
+use crate::git::branches::branches;
+
+use crate::git::main_branch::main_branch;
+use crate::git::tag::get_tag;
+use crate::utils::repo_config::repo_config;
+use rocket_dyn_templates::{context, Template};
+
+#[get("/<repo>/refs?<page>", rank = 2)]
+pub fn refs(repo: String, page: Option<usize>) -> Option<Template> {
+ let mut tags = get_tag(repo.clone(), 11, (page.unwrap_or(1)-1)*10, None);
+ let mut pages = 1;
+ let mut forward = false;
+ match tags {
+ Some(ref mut x) => {
+ pages = x.1/10+1;
+ if x.0.len() == 11 {
+ forward = true;
+ x.0.pop();
+ }
+ },
+ None => {}
+ }
+ Some(Template::render(
+ "repository/refs",
+ context! {
+ title: format!("/ :: {}", repo.clone()),
+ repo: repo.clone(),
+ config: repo_config(repo.clone()),
+ domain: CONFIG.domain.to_string(),
+ active: "refs",
+ current_dir_file: "/",
+ current_dir: "/",
+ payment: CONFIG.payment_link.clone(),
+ mailing_list: CONFIG.mailing_list.clone(),
+ branch: branches(repo.clone()),
+ tag: tags,
+ page_dec: page.unwrap_or(1)-1,
+ page_inc: page.unwrap_or(1)+1,
+ total_page: pages,
+ page: page.unwrap_or(1)
+ },
+ ))
+}
+
+#[get("/<repo>/refs/<name>", rank = 2)]
+pub fn refs_id(repo: String, name: String) -> Option<Template> {
+ let binding = get_tag(repo.clone(), 1, 0, Some(name))?;
+ let tag = binding.0.first()?;
+ Some(Template::render(
+ "repository/ref",
+ context! {
+ title: format!("/ :: {}", repo.clone()),
+ repo: repo.clone(),
+ config: repo_config(repo.clone()),
+ domain: CONFIG.domain.to_string(),
+ active: "refs",
+ current_dir_file: "/",
+ current_dir: "/",
+ payment: CONFIG.payment_link.clone(),
+ mailing_list: CONFIG.mailing_list.clone(),
+ tag: tag,
+ },
+ ))
+}
M src/repository/summary.rs => src/repository/summary.rs +2 -2
@@ 23,8 23,8 @@ pub fn repository(repo: String) -> Option<Template> {
active: "summary",
preview: get_commits(repo.clone(), 3, None, None),
main_branch,
- tag: match get_tag(repo.clone(), 1) {
- Some(x) => match x.get(0) {
+ tag: match get_tag(repo.clone(), 1, 0, None) {
+ Some(x) => match x.0.get(0) {
Some(x) => Some(x.clone()),
None => None
},
M src/repository/tree.rs => src/repository/tree.rs +2 -2
@@ 77,7 77,7 @@ pub fn tree(repo: String, branch: String, location: PathBufWithDotfiles) -> Opti
config: repo_config(repo.clone()),
domain: CONFIG.domain.to_string(),
active: "tree",
- commit: match get_commits(repo.clone(), 1, None, Some(format!("{}", location.get().display()).replace("//", "/"))) {
+ commit: match get_commits(repo.clone(), 1, Some(branch.clone()), Some(format!("{}", location.get().display()).replace("//", "/"))) {
Some(x) => match x.clone().get(0) {
Some(x) => Some(x.clone()),
None => None
@@ 104,7 104,7 @@ pub fn tree(repo: String, branch: String, location: PathBufWithDotfiles) -> Opti
config: repo_config(repo.clone()),
domain: CONFIG.domain.to_string(),
active: "tree",
- commit: match get_commits(repo.clone(), 1, None, Some(format!("{}", location.get().display()).replace("//", "/"))) {
+ commit: match get_commits(repo.clone(), 1, Some(branch.clone()), Some(format!("{}", location.get().display()).replace("//", "/"))) {
Some(x) => match x.clone().get(0) {
Some(x) => Some(x.clone()),
None => None
A templates/repository/ref.html.hbs +28 -0
@@ 0,0 1,28 @@
+{{#*inline "page"}}
+{{> navbar}}
+<div class="container">
+ <h3>{{tag.name}}
+ <small class="pull-right text-muted">
+ <span title="{{tag.commit.time_utc}}">{{tag.commit.time_relitive}}</span>
+ </small>
+ </h3>
+ <div class="row">
+ <div class="col-md-4">
+ <div class="form-group">
+ <a class="btn btn-primary btn-block" href="/{{repo}}/archive/{{tag.name}}.tar.gz">.tar.gz <span aria-hidden="true" class="icon icon-caret-right"><svg viewBox="0 0 192 512" xmlns="http://www.w3.org/2000/svg"><path d="M0 384.662V127.338c0-17.818 21.543-26.741 34.142-14.142l128.662 128.662c7.81 7.81 7.81 20.474 0 28.284L34.142 398.804C21.543 411.404 0 402.48 0 384.662z"></path></svg>
+ </span></a>
+ <a class="btn btn-default btn-block" href="/{{repo}}/tree/{{tag.name}}">browse <span aria-hidden="true" class="icon icon-caret-right"><svg viewBox="0 0 192 512" xmlns="http://www.w3.org/2000/svg"><path d="M0 384.662V127.338c0-17.818 21.543-26.741 34.142-14.142l128.662 128.662c7.81 7.81 7.81 20.474 0 28.284L34.142 398.804C21.543 411.404 0 402.48 0 384.662z"></path></svg>
+ </span></a>
+ </div>
+ </div>
+ <div class="col-md-8">
+ <div class="event-list">
+ <div class="event">
+ <pre style="padding-bottom: 0;">{{tag.body}}</pre>
+ </div>
+ </div>
+ </div>
+ </div>
+</div>
+{{/inline}}
+{{> layout}}
A templates/repository/refs.html.hbs +83 -0
@@ 0,0 1,83 @@
+{{#*inline "page"}}
+{{> navbar}}
+<div class="container">
+ <div class="row" style="margin-bottom: 1rem">
+ <div class="col-md-8">
+ {{#each tag.0}}
+ <div class="event">
+ <h4 style="margin-bottom: 0.5rem">
+ <a href="/{{../repo}}/refs/{{this.name}}">
+ {{this.name}}
+ </a>
+ <small class="pull-right text-muted">
+ <span title="{{this.commit.time_utc}}">{{this.commit.time_relitive}}</span>
+ <a href="/{{../repo}}/archive/{{this.name}}.tar.gz" rel="nofollow" style="margin-left: 0.5rem">.tar.gz <span aria-hidden="true" class="icon icon-caret-right"><svg viewBox="0 0 192 512" xmlns="http://www.w3.org/2000/svg"><path d="M0 384.662V127.338c0-17.818 21.543-26.741 34.142-14.142l128.662 128.662c7.81 7.81 7.81 20.474 0 28.284L34.142 398.804C21.543 411.404 0 402.48 0 384.662z"></path></svg>
+ </span></a>
+ <a href="/{{../repo}}/tree/{{this.name}}" style="margin-left: 0.5rem">browse <span aria-hidden="true" class="icon icon-caret-right"><svg viewBox="0 0 192 512" xmlns="http://www.w3.org/2000/svg"><path d="M0 384.662V127.338c0-17.818 21.543-26.741 34.142-14.142l128.662 128.662c7.81 7.81 7.81 20.474 0 28.284L34.142 398.804C21.543 411.404 0 402.48 0 384.662z"></path></svg>
+ </span></a>
+ <a href="/{{../repo}}/log/{{this.name}}" style="margin-left: 0.5rem">log <span aria-hidden="true" class="icon icon-caret-right"><svg viewBox="0 0 192 512" xmlns="http://www.w3.org/2000/svg"><path d="M0 384.662V127.338c0-17.818 21.543-26.741 34.142-14.142l128.662 128.662c7.81 7.81 7.81 20.474 0 28.284L34.142 398.804C21.543 411.404 0 402.48 0 384.662z"></path></svg>
+ </span></a>
+ </small>
+ </h4>
+ <pre style="padding-bottom: 0;">{{this.body}}</pre>
+</div>
+ {{/each}}
+ {{#if (ne total_page 1)}}
+ <div class="row">
+ <div class="col-4">
+ {{#if (ne page 1)}}
+ <a class="btn btn-default" href="?page={{page_dec}}">
+ <span aria-hidden="true" class="icon icon-caret-left">
+ <svg viewBox="0 0 192 512" xmlns="http://www.w3.org/2000/svg">
+ <path d="M192 127.338v257.324c0 17.818-21.543 26.741-34.142 14.142L29.196 270.142c-7.81-7.81-7.81-20.474 0-28.284l128.662-128.662c12.599-12.6 34.142-3.676 34.142 14.142z"></path>
+ </svg>
+ </span>
+ prev
+ </a>
+ {{/if}}
+ </div>
+ <div class="col-4 text-centered">
+ {{page}} / {{ total_page }}
+ </div>
+ {{#if (ne page total_page)}}
+ <div class="col-4 text-right">
+ <a class="btn btn-default" href="?page={{page_inc}}">
+ next
+ <span aria-hidden="true" class="icon icon-caret-right">
+ <svg viewBox="0 0 192 512" xmlns="http://www.w3.org/2000/svg">
+ <path d="M0 384.662V127.338c0-17.818 21.543-26.741 34.142-14.142l128.662 128.662c7.81 7.81 7.81 20.474 0 28.284L34.142 398.804C21.543 411.404 0 402.48 0 384.662z"></path>
+ </svg>
+ </span>
+ </a>
+ </div>
+ {{/if}}
+ </div>
+ {{/if}}
+ </div>
+ <div class="col-md-4">
+ <h3>Branches</h3>
+ <div class="event-list">
+ {{#each branch}}
+ <div class="event">{{this.branch}}
+ <div>
+ <a href="/{{../repo}}/commit/{{this.commit.commit_hash}}" title="{{this.commit.commit_hash}}">{{this.commit.commit_hash_short}}</a> — {{this.commit.commitie}}
+ <small class="pull-right">
+ <a href="/{{../repo}}/log?from={{this.commit.commit_hash}}#log-{{this.commit.commit_hash}}" id="log-{{this.commit_hash}}"><span title="{{this.commit.time_utc}}">{{this.commit.time_relitive}}</span></a>
+ </small>
+ </div>
+ <div class="row" style="margin-top: 0.5rem">
+ <div class="col">
+ <a class="btn btn-block btn-primary" href="/{{../repo}}/tree/{{this.branch}}">browse <span aria-hidden="true" class="icon icon-caret-right"><svg viewBox="0 0 192 512" xmlns="http://www.w3.org/2000/svg"><path d="M0 384.662V127.338c0-17.818 21.543-26.741 34.142-14.142l128.662 128.662c7.81 7.81 7.81 20.474 0 28.284L34.142 398.804C21.543 411.404 0 402.48 0 384.662z"></path></svg></span></a>
+ </div>
+ <div class="col">
+ <a class="btn btn-block btn-default" href="/{{../repo}}/log/{{this.branch}}">log <span aria-hidden="true" class="icon icon-caret-right"><svg viewBox="0 0 192 512" xmlns="http://www.w3.org/2000/svg"><path d="M0 384.662V127.338c0-17.818 21.543-26.741 34.142-14.142l128.662 128.662c7.81 7.81 7.81 20.474 0 28.284L34.142 398.804C21.543 411.404 0 402.48 0 384.662z"></path></svg></span></a>
+ </div>
+ </div>
+ </div>
+ {{/each}}
+ </div>
+ </div>
+ </div>
+</div>
+{{/inline}}
+{{> layout}}
M templates/repository/summary.html.hbs => templates/repository/summary.html.hbs +2 -2
@@ 52,7 52,7 @@
{{#if tag}}
<dt>ref</dt>
<dd>
- <a href="/{{repo}}/refs/{{tag}}">
+ <a href="/{{repo}}/refs/{{tag.name}}">
release notes
<span aria-hidden="true" class="icon icon-caret-right">
<svg viewBox="0 0 192 512" xmlns="http://www.w3.org/2000/svg">
@@ 82,4 82,4 @@
</div>
</div>
{{/inline}}
-{{> layout}}>
\ No newline at end of file
+{{> layout}}