Compare commits

...

10 Commits

Author SHA1 Message Date
諏訪子 0204b74295 ごめん 2023-06-22 12:32:57 +09:00
諏訪子 16407e0270 DEBUG値を追加 2023-06-15 14:22:09 +09:00
諏訪子 fd770ecb4d おちんちん 2023-06-11 22:32:42 +09:00
諏訪子 dd70375832 . 2023-06-11 22:18:51 +09:00
諏訪子 96c4ff2d42 ファイルは正しい場所に置く #12 2023-06-11 22:02:45 +09:00
諏訪子 c6b78fa0c8 . 2023-06-11 21:38:25 +09:00
諏訪子 088d077ac8 コンフィグ 2023-06-11 21:16:45 +09:00
諏訪子 20818ce26d 忘れた 2023-06-11 20:35:37 +09:00
諏訪子 8742c84e47 コミット履歴( #6 2023-06-11 19:23:20 +09:00
諏訪子 5bd624af13 面倒くさい… 2023-06-11 19:21:28 +09:00
9 changed files with 334 additions and 100 deletions

View File

@ -6,3 +6,6 @@
* フーターを追加
* ユーザーページにアクセスしやすくに
* レポジトリヘッダー
* ZIP→TAR.GZ
* カッシュを削除
* コミット履歴

View File

@ -1,6 +1,18 @@
NAME=gitlin
VERSION=1.0.0
#VERSION=$(cat utils/version.go | grep "var Ver" | awk '{print $4}' | sed "s/\"//g")
# Linux、Solaris、Haiku
PREFIX=/usr
# FreeBSD、OpenBSD
#PREFIX=/usr/local
# NetBSD
#PREFIX=/usr/pkg
# Linux、OpenBSD、Solaris、Haiku
CNFPREFIX=/etc
# FreeBSD
#CNFPREFIX=/usr/local/etc
# NetBSD
#CNFPREFIX=/usr/pkg/etc
CC=CGO_ENABLED=0 go build
# リリース。なし=デバッグ。
RELEASE=-ldflags="-s -w" -buildvcs=false
@ -19,4 +31,22 @@ dist: clean
tar zcfv ${NAME}-${VERSION}.tar.gz ${NAME}-${VERSION}
rm -rf ${NAME}-${VERSION}
.PHONY: all options clean dist
install:
mkdir -p ${DESTDIR}/var/${NAME}
chmod 755 ${DESTDIR}/var/${NAME}
cp -rf views ${DESTDIR}/var/${NAME}
cp -rf public ${DESTDIR}/var/${NAME}
mkdir -p ${DESTDIR}${PREFIX}/bin
cp -f ${NAME} ${DESTDIR}${PREFIX}/bin
chmod 755 ${DESTDIR}${PREFIX}/bin/${NAME}
mkdir -p ${DESTDIR}${CNFPREFIX}/${NAME}
chmod 755 ${DESTDIR}${CNFPREFIX}/${NAME}
touch ${DESTDIR}${CNFPREFIX}/${NAME}/${NAME}.conf
chmod 644 ${DESTDIR}${CNFPREFIX}/${NAME}/${NAME}.conf
uninstall:
rm -f ${DESTDIOR}${PREFIX}/bin/${NAME}\
${DESTDIR}${MANPREFIX}/man1/${NAME}.1\
${DESTDIR}${CNFPREFIX}/${NAME}
.PHONY: all options clean dist install uninstall

View File

@ -9,7 +9,7 @@ Gitlinは[GotHub](https://codeberg.org/gothub/gothub)のフォークです。
* Go 1.20以上
* nginx又はOpenBSDのrelayd
* 良いOS (GNU/Linux、OpenBSD、又はFreeBSD)
* 良いOS (GNU/Linux、OpenBSD、NetBSD、OpenIndiana、又はFreeBSD)
## インストールする方法
@ -26,7 +26,7 @@ nvim /etc/rc.d/gitlin
```
#!/bin/ksh
daemon="/var/www/htdocs/DOMAIN/gitlin serve"
daemon="/usr/local/bin/gitlin serve"
. /etc/rc.d/rc.subr
@ -42,60 +42,6 @@ rcctl enable gitlin
rcctl start gitlin
```
### FreeBSD
```sh
nvim /usr/local/etc/rc.d/gitlin
```
```
#!/bin/sh
# PROVIDE: gitlin
# REQUIRE: NETWORKING SYSLOG
# KEYWORD: shutdown
#
# Add the following lines to /etc/rc.conf to enable gitlin:
. /etc/rc.subr
name="gitlin"
rcvar="gitlin_enable"
load_rc_config $name
: ${gitlin_enable:="NO"}
: ${gitlin_facility:="daemon"}
: ${gitlin_priority:="debug"}
command="/var/htdocs/DOMAIN/${name}"
procname="/var/htdocs/DOMAIN/${name}"
pidfile="/var/run/${name}.pid"
start_cmd="${name}_start"
gitlin_start() {
for d in /var/db/gitlin /var/log/gitlin; do
if [ ! -e "$d" ]; then
mkdir "$d"
fi
done
/usr/sbin/daemon -S -l ${gitlin_facility} -s ${gitlin_priority} -T ${name} \
-p ${pidfile} \
/usr/bin/env -i \
"PATH=/var/htdocs/DOMAIN:${PATH}" \
$command
}
run_rc_command "$1"
```
```sh
sysrc gitlin_enable=YES
service start gitlin
```
### Crux
```sh
@ -141,7 +87,7 @@ esac
# End of file
```
### Devuan/Debian/Ubuntu/Arch/Artix/AlmaLinux等
### Devuan
```sh
nvim /etc/init.d/gitlin
@ -160,7 +106,7 @@ DAEMON=/usr/bin/$NAME
start () {
echo "Gitlinサーバーは開始中\n"
/usr/bin/gitlin -s 9910 &>/dev/null &
/usr/bin/gitlin -s 9715 &>/dev/null &
touch /var/lock/subsys/gitlin
echo
}
@ -229,7 +175,7 @@ relay www {
listen on $relayd_address port 443 tls
protocol $relayd_address
forward to <gitlin> check tcp port 9910
forward to <gitlin> check tcp port 9715
}
```
@ -238,7 +184,6 @@ relay www {
```sh
server {
server_name DOMAIN www.DOMAIN;
root /var/www/htdocs/gitlin;
access_log off;
error_log off;
@ -252,7 +197,7 @@ server {
}
location / {
proxy_pass http://localhost:9910;
proxy_pass http://localhost:9715;
}
listen [::]:443 ssl ipv6only=on;

View File

@ -4,9 +4,8 @@ import (
"fmt"
"os"
"gitler.moe/suwako/gitlin/utils"
"github.com/spf13/cobra"
_ "github.com/joho/godotenv/autoload"
)
var envCmd = &cobra.Command{
@ -19,6 +18,7 @@ var envCmd = &cobra.Command{
}
func init() {
utils.LoadCnf()
rootCmd.AddCommand(envCmd)
}

View File

@ -3,6 +3,7 @@ package gitlin
import (
"fmt"
"os"
"os/user"
"github.com/spf13/cobra"
)
@ -21,18 +22,22 @@ func init() {
}
type Vars struct {
IPLogging bool
URLLogging bool
UserAgentLogging bool
DiagnosticLogging bool
PrivacyPolicy string
InstanceCountry string
InstanceProvider string
CloudflareStatus string
Proxying string
IPLogging, URLLogging, UserAgentLogging, DiagnosticLogging bool
PrivacyPolicy, InstanceCountry, InstanceProvider, CloudflareStatus, Proxying string
}
func setup() {
cur, err := user.Current()
if err != nil {
fmt.Println("現在のユーザーのUIDを見つけられませんでした。", err)
return
}
if cur.Uid != "0" {
fmt.Println("rootとして実行して下さい。 sudo gitlin setup 又は doas gitlin setup")
return
}
fmt.Println("Gitlin setup wizard")
fmt.Println("This wizard will help you setup your Gitlin instance.")
@ -40,7 +45,7 @@ func setup() {
vars := Vars{}
// ask user for information about IP logging
fmt.Print("Do you log IP addresses of users? (y/n) ")
fmt.Print("Do you log IP addresses of users? (y/N) ")
var ipLogging string
fmt.Scanln(&ipLogging)
if ipLogging == "y" {
@ -52,7 +57,7 @@ func setup() {
}
// ask user for information about URL request logging
fmt.Print("Do you log URL requests of users? (y/n) ")
fmt.Print("Do you log URL requests of users? (y/N) ")
var urlLogging string
fmt.Scanln(&urlLogging)
if urlLogging == "y" {
@ -62,7 +67,7 @@ func setup() {
}
// ask user for information about User-Agent logging
fmt.Print("Do you log your users User-Agent? (y/n) ")
fmt.Print("Do you log your users User-Agent? (y/N) ")
var uaLogging string
fmt.Scanln(&uaLogging)
if uaLogging == "y" {
@ -72,7 +77,7 @@ func setup() {
}
// ask user for information about diagnostic information logging
fmt.Print("Do you log diagnostic information? (y/n) ")
fmt.Print("Do you log diagnostic information? (y/N) ")
var diagLogging string
fmt.Scanln(&diagLogging)
if diagLogging == "y" {
@ -82,7 +87,7 @@ func setup() {
}
// ask user about privacy policy
fmt.Print("Do you have a privacy policy? (y/n) ")
fmt.Print("Do you have a privacy policy? (y/N) ")
var privacyPolicy string
fmt.Scanln(&privacyPolicy)
if privacyPolicy == "y" {
@ -116,7 +121,7 @@ func setup() {
}
// ask user about Cloudflare status
fmt.Print("Are you using Cloudflare? (y/n) ")
fmt.Print("Are you using Cloudflare? (y/N) ")
var cloudflare string
fmt.Scanln(&cloudflare)
if cloudflare == "y" {
@ -126,20 +131,20 @@ func setup() {
}
// ask user whether they want proxying enabled
fmt.Print("Do you want proxying enabled? (y/n) ")
fmt.Print("Do you want proxying enabled? (Y/n) ")
var proxying string
fmt.Scanln(&proxying)
if proxying == "y" {
if proxying == "y" || proxying == "" {
vars.Proxying = "true"
} else {
vars.Proxying = "false"
}
// save to .env file
fmt.Println("Saving environment variables to .env file...")
f, err := os.Create(".env")
// save to gitlin.conf file
fmt.Println("Saving environment variables to config file...")
f, err := os.Create("/etc/gitlin/gitlin.conf")
if err != nil {
fmt.Println("Error creating .env file: ", err)
fmt.Println("Error creating config file: ", err)
os.Exit(1)
}
defer f.Close()
@ -156,7 +161,7 @@ func setup() {
f.WriteString("GITLIN_INSTANCE_COUNTRY=" + vars.InstanceCountry + "\n")
f.WriteString("GITLIN_INSTANCE_PROVIDER=" + vars.InstanceProvider + "\n")
f.WriteString("GITLIN_INSTANCE_CLOUDFLARE=" + vars.CloudflareStatus + "\n")
f.WriteString("GITLIN_PROXYING_ENABLED=" + vars.Proxying)
f.WriteString("GITLIN_PROXYING_ENABLED=" + vars.Proxying + "\n")
println("All done! You can now start your Gitlin instance with 'gitlin serve'.")
println("You can review the environment variables with 'gitlin env'.")

149
pages/commits.go Normal file
View File

@ -0,0 +1,149 @@
package pages
import (
"log"
"net/http"
"net/url"
"os"
"strings"
"time"
"gitler.moe/suwako/gitlin/utils"
"github.com/gocolly/colly"
"github.com/gofiber/fiber/v2"
)
type (
Commits struct {
Date, Next, Prev string
Commit []Commit
}
Commit struct {
Mess, User, Id, IdShort, Issue, Ava string
}
)
func HandleCommits (c *fiber.Ctx) error {
var commitsArray []Commits
branch := ""
if strings.Count(c.Params("branch"), "")-1 > 0 {
branch = c.Params("branch")
}
repoUrl := strings.TrimSuffix(c.Params("repo"), ".git")
endurl := ""
if branch != "" {
endurl = "/" + branch
if c.Query("after") != "" {
endurl += "?after=" + url.QueryEscape(c.Query("after")) + "&branch=" + url.QueryEscape(c.Query("branch")) + "&qualified_name=" + url.QueryEscape(c.Query("qualified_name"))
} else if c.Query("before") != "" {
endurl += "?before=" + url.QueryEscape(c.Query("before")) + "&branch=" + url.QueryEscape(c.Query("branch")) + "&qualified_name=" + url.QueryEscape(c.Query("qualified_name"))
}
} else if (c.Query("author") != "") {
if c.Query("after") != "" {
endurl = "?after=" + url.QueryEscape(c.Query("after")) + "&author=" + url.QueryEscape(c.Query("author"))
} else if c.Query("before") != "" {
endurl = "?before=" + url.QueryEscape(c.Query("before")) + "&author=" + url.QueryEscape(c.Query("author"))
} else {
endurl = "?author=" + url.QueryEscape(c.Query("author"))
}
}
resp, err := http.Get("https://github.com/" + c.Params("user") + "/" + repoUrl + "/commits" + endurl)
if err != nil {
log.Println(err)
}
if resp.StatusCode == 404 {
return c.Status(404).Render("error", fiber.Map {
"title": "Error",
"ver": utils.Ver,
"ves": utils.Ves,
"error": "Repository " + c.Params("user") + "/" + repoUrl + "/commits" + endurl + " not found",
})
}
Scrape := Commits{}
ua, ok := os.LookupEnv("GITLIN_USER_AGENT")
if !ok {
ua = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.0.0 Safari/537.36"
}
sc := colly.NewCollector(colly.AllowedDomains("github.com"), colly.UserAgent(ua))
sc.Limit(&colly.LimitRule {
DomainGlob: "github.githubassets.com/*",
Delay: 30 * time.Second,
RandomDelay: 30 * time.Second,
})
sc.OnRequest(func(r *colly.Request) {
r.Headers.Set("Cache-Control", "no-cache, no-store, must-revalidate")
r.Headers.Set("Pragma", "no-cache")
r.Headers.Set("Expires", "0")
})
sc.OnHTML("div.repository-content div.container-xl div.js-navigation-container", func (e *colly.HTMLElement) {
e.ForEach("div.TimelineItem div.TimelineItem-body", func (i int, el *colly.HTMLElement) {
tdate := strings.TrimPrefix(el.ChildText("h2.f5"), "Commits on ")
td, e := time.Parse("Jan 2, 2006", tdate)
if e != nil {
log.Println(e)
}
Scrape.Date = td.Format("2006年01月02日")
el.ForEach("ol.Box", func (ij int, eli *colly.HTMLElement) {
var mess, id, issue, idshort, user, ava string
var commitArray []Commit
eli.ForEach("li.Box-row", func (ijk int, elin *colly.HTMLElement) {
mess, id, issue, idshort, user, ava = "", "", "", "", "", ""
mess += elin.ChildText("div.Details p.mb-1 a")
issue = strings.ReplaceAll(elin.ChildAttr("div.Details p.mb-1 a.issue-link", "href"), "https://github.com/" + c.Params("user") + "/" + repoUrl + "/pull/", "")
id = strings.TrimPrefix(elin.ChildAttr("div.Details p.mb-1 a", "href"), "/" + c.Params("user") + "/" + repoUrl + "/commit/")
idshort = id[:7]
eli.ForEach("div.Details div.mt-1 div.f6", func (iju int, eliu *colly.HTMLElement) {
user = eliu.ChildText("a")
})
eli.ForEach("div.Details div.d-flex div.AvatarStack div.AvatarStack-body a.avatar", func (ijh int, elia *colly.HTMLElement) {
ava = elia.ChildAttr("img", "src")
if (strings.Contains(ava, "https://avatars.githubusercontent.com/in")) {
ava = strings.ReplaceAll(ava, "https://avatars.githubusercontent.com/in", "/avatar")
} else {
ava = strings.ReplaceAll(ava, "https://avatars.githubusercontent.com/u", "/avatar")
}
})
commitArray = append(commitArray, Commit{
Mess: mess,
User: user,
Id: id,
IdShort: idshort,
Issue: issue,
Ava: ava,
})
})
Scrape.Commit = commitArray
})
commitsArray = append(commitsArray, Scrape)
})
})
sc.OnHTML(`div.repository-content div.container-xl div.paginate-container div.BtnGroup a:contains("Newer")`, func(e *colly.HTMLElement) {
Scrape.Next = strings.TrimPrefix(e.Attr("href"), "https://github.com")
})
sc.OnHTML(`div.repository-content div.container-xl div.paginate-container div.BtnGroup a:contains("Older")`, func(e *colly.HTMLElement) {
Scrape.Prev = strings.TrimPrefix(e.Attr("href"), "https://github.com")
})
sc.Visit("https://github.com/" + c.Params("user") + "/" + repoUrl + "/commits" + endurl)
return c.Render("commits", fiber.Map{
"title": c.Params("user") + "/" + repoUrl + "/commits" + endurl,
"username": c.Params("user"),
"reponame": repoUrl,
"branch": branch,
"author": c.Query("author"),
"ver": utils.Ver,
"ves": utils.Ves,
"prev": Scrape.Prev,
"next": Scrape.Next,
"commits": commitsArray,
})
}

View File

@ -12,19 +12,24 @@ import (
"gitler.moe/suwako/gitlin/utils"
"github.com/gofiber/fiber/v2"
"github.com/gofiber/fiber/v2/middleware/cache"
"github.com/gofiber/fiber/v2/middleware/compress"
"github.com/gofiber/fiber/v2/middleware/limiter"
// For debugging purposes
// "github.com/gofiber/fiber/v2/middleware/logger"
"github.com/gofiber/fiber/v2/middleware/recover"
"github.com/gofiber/template/html"
_ "github.com/joho/godotenv/autoload"
)
func Serve(port string) {
engine := html.New("./views", ".html")
utils.LoadCnf()
isdebug, ok := os.LookupEnv("GITLIN_DEBUG")
engine := html.New("/var/gitlin/views", ".html")
if !ok {
isdebug = "0"
}
if isdebug != "0" {
engine = html.New("./views", ".html")
}
engine.AddFunc(
// Add unescape function. This is needed to render HTML from Markdown.
@ -62,9 +67,6 @@ func Serve(port string) {
},
})
app.Use(cache.New(cache.Config{
Expiration: 5 * time.Minute,
}))
// For debugging purposes
// app.Use(logger.New(logger.Config{
// Format: "[${ip}]:${port} ${status} - ${method} ${path} ${queryParams}\n",
@ -115,11 +117,19 @@ func Serve(port string) {
})
app.Get("/", pages.HandleIndex)
app.Static("/css", "./public/css", staticConfig)
app.Static("/robots.txt", "./public/robots.txt", staticConfig)
app.Static("/favicon.ico", "./public/assets/favicon.ico", staticConfig)
app.Static("/logo.png", "./public/assets/logo.png", staticConfig)
app.Static("/git.png", "./public/assets/git.png", staticConfig)
if isdebug == "0" {
app.Static("/css", "/var/gitlin/public/css", staticConfig)
app.Static("/robots.txt", "/var/gitlin/public/robots.txt", staticConfig)
app.Static("/favicon.ico", "/var/gitlin/public/assets/favicon.ico", staticConfig)
app.Static("/logo.png", "/var/gitlin/public/assets/logo.png", staticConfig)
app.Static("/git.png", "/var/gitlin/public/assets/git.png", staticConfig)
} else {
app.Static("/css", "./public/css", staticConfig)
app.Static("/robots.txt", "./public/robots.txt", staticConfig)
app.Static("/favicon.ico", "./public/assets/favicon.ico", staticConfig)
app.Static("/logo.png", "./public/assets/logo.png", staticConfig)
app.Static("/git.png", "./public/assets/git.png", staticConfig)
}
app.Get("/about", pages.HandleAbout)
app.Get("/explore", ratelimiter, pages.HandleExplore)
app.Get("/:user", pages.HandleUser)
@ -186,13 +196,14 @@ func Serve(port string) {
app.Get("/gist/:user/:gistID", pages.HandleGist)
app.Get("/download/gist/:user/:gistID/:revision", func(c *fiber.Ctx) error {
if proxying == "true" {
utils.ProxyRequest(c, "https://gist.github.com/"+c.Params("user")+"/"+c.Params("gistID")+"/archive/"+c.Params("revision")+".zip")
utils.ProxyRequest(c, "https://gist.github.com/"+c.Params("user")+"/"+c.Params("gistID")+"/archive/"+c.Params("revision")+".tar.gz")
return nil
} else {
c.Redirect("https://gist.github.com/" + c.Params("user") + "/" + c.Params("gistID") + "/archive/" + c.Params("revision") + ".zip")
c.Redirect("https://gist.github.com/" + c.Params("user") + "/" + c.Params("gistID") + "/archive/" + c.Params("revision") + ".tar.gz")
return nil
}
})
app.Get("/:user/:repo/commits/:branch?", pages.HandleCommits)
api := app.Group("/api")
v1 := api.Group("/v1")

32
utils/autoconf.go Normal file
View File

@ -0,0 +1,32 @@
package utils
import (
"log"
"os"
"runtime"
"github.com/joho/godotenv"
)
func LoadCnf () {
homedir, herr := os.UserHomeDir()
if herr != nil {
log.Fatal("ホームフォルダを見つけられませんでした。", herr)
}
homeconf := homedir + "/.config/gitlin.conf"
conf := "/etc/gitlin/gitlin.conf" // Linux、OpenBSD、Solaris、Haiku
if runtime.GOOS == "freebsd" {
conf = "/usr/local/gitlin/gitlin.conf" // FreeBSDのみ
} else if runtime.GOOS == "netbsd" {
conf = "/usr/pkg/gitlin/gitlin.conf" // NetBSDのみ
}
err := godotenv.Load(homeconf)
if err != nil {
err2 := godotenv.Load(conf)
if err2 != nil {
log.Fatal("コンフィグファイルを見つけられませんでした。")
}
}
}

59
views/commits.html Normal file
View File

@ -0,0 +1,59 @@
{{ template "header" . }}
<style>
td {
padding: 16px 0;
}
</style>
<main>
<div class="user-profile">
<h1>
<a href="/{{.username}}">{{.username}}</a>
/
<a href="/{{.username}}/{{.reponame}}">{{.reponame}}</a>
</h1>
<h2>
{{if ne "" .branch}}
{{.branch}}で
{{else}}
{{.author}}さん
{{end}}のコミット
</h2>
{{if .commits}}
{{range $key, $value := .commits}}
<h3>{{$value.Date}}</h3>
<table class="user-readme-text file-table">
<tbody>
{{range $k, $v := $value.Commit}}
<tr class="file-u-list">
<td>
<a href="/{{$.username}}/{{$.reponame}}/commit/{{$v.Id}}">{{$v.Mess}}</a><br />
<a href="/{{$.username}}/{{$.reponame}}/commits?author={{$v.User}}">{{$v.User}}</a>さんは{{$value.Date}}でコミットしました
</td>
<td width="70" style="vertical-align: top;">
{{if $v.Issue}}
<a href="/{{$.username}}/{{$.reponame}}/pull/{{$v.Issue}}">#{{$v.Issue}}</a>
{{end}}
</td>
<td width="80" style="vertical-align: top;">
<a href="/{{$.username}}/{{$.reponame}}/commit/{{$v.Id}}">{{.IdShort}}</a>
</td>
</tr>
{{end}}
</tbody>
</table>
{{end}}
{{end}}
</div>
{{if .commits}}
{{if or (ne "" .prev) (ne "" .next)}}
<div class="button-parent">
{{if ne "" .next}}<a class="button" href="{{.next}}"></a>{{end}}
{{if ne "" .prev}}<a class="button" href="{{.prev}}">戻る</a>{{end}}
</div>
{{end}}
{{end}}
</main>
{{ template "footer" . }}