commit 32c540a903c44eb372ce070d3f4510fbb34bd5cf Author: m455 Date: Fri Dec 2 16:41:55 2022 -0500 first commit diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..19b63d1 --- /dev/null +++ b/Makefile @@ -0,0 +1,26 @@ +DEPS = utf8 lowdown +SRC = main.scm +DIR_INSTALL ?= /usr/local/bin +DIR_BUILD = . +BIN = repo2html + +all: compile + +compile: + mkdir $(DIR_BUILD)/ + csc -O3 -static ./$(SRC) -o $(DIR_BUILD)/$(BIN) + rm ./$(DIR_BUILD)/$(BIN).link + @echo "Finished compiling a static binary in $(DIR_BUILD)/$(BIN)!" + +dependencies: + chicken-install $(DEPS) + +install: + install -Dm755 $(DIR_BUILD)/$(BIN) -D $(DIR_INSTALL)/$(PROG) + +uninstall: + rm $(DIR_INSTALL)/$(PROG) + +clean: + rm $(DIR_BUILD)/$(BIN) + diff --git a/README.md b/README.md new file mode 100644 index 0000000..27700ae --- /dev/null +++ b/README.md @@ -0,0 +1,55 @@ +# repo2html + +a tool that generates an html view of a git repository. + +## features + +TODO + +## caveats + +TODO + +## disclaimer + +TODO + +## requirements + +TODO + +## quickstart + +TODO + +## compilation + +``` +sudo make dependencies +make +sudo make install +``` + +## installation + +TODO + +## post installation + +TODO (git user, ssh, ufw ports, web directory, git-daemon, mkdir /home/git/projects, post-receive hook, systemd service) + +## usage + +TODO + +## configuration + +TODO + +## todos + +TODO + +## hopes + +TODO diff --git a/git-daemon.service b/git-daemon.service new file mode 100644 index 0000000..b9f0527 --- /dev/null +++ b/git-daemon.service @@ -0,0 +1,15 @@ +[Unit] +Description=Start Git Daemon + +[Service] +ExecStart=/usr/bin/git daemon --base-path=/home/git/projects --export-all --reuseaddr --informative-errors --verbose +Restart=always +RestartSec=500ms +StandardOutput=syslog +StandardError=syslog +SyslogIdentifier=git-daemon +User=git +Group=git + +[Install] +WantedBy=multi-user.target diff --git a/main.scm b/main.scm new file mode 100644 index 0000000..15efeb2 --- /dev/null +++ b/main.scm @@ -0,0 +1,226 @@ +;; how to use this script +;; 1. cd into a bare git repository +;; 2. run the following, changing any values you want: +;; export GIT_WWW=/var/www/git/ GIT_WWW_CLONE_URL=git://git.m455.casa GIT_WWW_TITLE=git.m455.casa GIT_WWW_DESCRIPTION="m455's git repositories" GIT_WWW_H1=git.m455.casa; csi -s ../main.scm +;; i figured i would use environment variables instead of a config file, +;; because folks are just going to run this as a post-receive hook anyway, so +;; why not all just configure it all in the post-receive hook like so? +;; (assuming git-www is in your $PATH, and assuming git-www is a compiled +;; version of git-www.scm): +;; --------------------------------- +;; #!/bin/sh +;; export GIT_WWW=/var/www/git/ +;; export GIT_WWW_CLONE_URL=git://git.m455.casa +;; export GIT_WWW_TITLE=git.m455.casa +;; export GIT_WWW_DESCRIPTION="m455's git repositories" +;; export GIT_WWW_H1=git.m455.casa +;; git-www +;; --------------------------------- + +;; TODO: +;; [x] replace all repository-name with *repository-name* +;; [x] replace all repository-directory with *repository-directory* +;; [x] remove all passed around parameters for repo name and directory +;; [x] move html-body-contents into final html-template format except use +;; string translate for named variables in the html-template +;; Nice-to-haves: +;; [ ] nav link: License (look for LICENSE file) +;; [ ] nav link: Contributors +;; [ ] nav link: Releases +;; [ ] clickable line numbers in source files +;; [ ] render images +;; [ ] make repos with more files and directories less daunting (recursively generate a files list page for each directory in a repo?) +(import utf8 + lowdown + (chicken string) + (chicken port) + (chicken io) + (chicken process) + (chicken process-context) + (chicken format) + (chicken pathname) + (chicken file)) + +;; decided to make these two buggers globals because i passed them around +;; between functions so much +(define *repository-name* #f) +(define *repository-directory* #f) + +(define WEB-DIRECTORY (let ((environment-variable (get-environment-variable "GIT_WWW"))) + ;; this seems silly, but i'm not sure how else i should do it haha + (if environment-variable environment-variable "/var/www/git"))) + +(define CLONE-URL (let ((environment-variable (get-environment-variable "GIT_WWW_CLONE_URL"))) + ;; this seems silly, but i'm not sure how else i should do it haha + (if environment-variable environment-variable "git://git.example.com"))) + +(define TITLE (let ((environment-variable (get-environment-variable "GIT_WWW_TITLE"))) + (if environment-variable environment-variable "my git repositories"))) + +(define DESCRIPTION (let ((environment-variable (get-environment-variable "GIT_WWW_DESCRIPTION"))) + (if environment-variable environment-variable "my git repositories"))) + +(define H1 (let ((environment-variable (get-environment-variable "GIT_WWW_H1"))) + (if environment-variable environment-variable "git.example.com"))) + +(define HTML-TEMPLATE + #< + + +{{title}} + + + + + + + +

{{h1}}

+

{{repository-name}}

+

clone url: {{clone-url}}/{{repository-name}}

+ +
+{{body-contents}} + + +string-block +) + +(define (write-file file contents) + (with-output-to-file file (lambda () (display contents)))) + +(define (populate-html-template body-contents) + (string-translate* + HTML-TEMPLATE + `( + ("{{title}}" . ,TITLE) + ("{{description}}" . ,DESCRIPTION) + ("{{h1}}" . ,H1) + ("{{clone-url}}" . ,CLONE-URL) + ("{{repository-name}}" . ,*repository-name*) + ("{{body-contents}}" . ,body-contents)))) + +(define (in-git-directory?) + (if (equal? (call-with-input-pipe "git rev-parse --is-bare-repository 2> /dev/null" read-line) "true") + #t + #f)) + +(define (get-repository-name) + (pathname-strip-directory (current-directory))) + ; (call-with-input-pipe "git config --get remote.origin.url" read-line))) + +(define (git-repository->paths-list) + (call-with-input-pipe "git ls-tree -r --name-only HEAD" read-lines)) + +(define (git-file->string path) + (string-intersperse + (call-with-input-pipe (format "git show HEAD:~a" path) read-lines) + "\n")) + + +(define (clean-html str) + (string-translate* str '(("&" . "&") + ("<" . "<") + (">" . ">") + ("\"" . """) + ("'" . "'")))) + +(define (md->html markdown-string) + (with-output-to-string + (lambda () + (markdown->html markdown-string)))) + +(define (generate-list-of-files source-files-list) + (if (null? source-files-list) + "" + (let* ((source-file (car source-files-list)) + (link-url (string-append source-file ".html"))) ;; src/main.scm.html + (string-append (format "
  • ~a
  • \n" link-url source-file) + (generate-list-of-files (cdr source-files-list)))))) + +(define (generate-source-file source-file) ;; src/main.scm + (let* ((source-file-directory (pathname-directory source-file)) ;; src or #f + (output-directory (if source-file-directory + (make-pathname *repository-directory* source-file-directory) ;; //src + *repository-directory*))) ;; / + ;; create directories that mimic the path of the source file, so when + ;; someone clicks a link to view the contents of a source file, the URL + ;; matches up with the path of the source file. + ;; i guess another reason to do this is to avoid conflicts with files that + ;; have the same name, but exist in different directories. + (create-directory output-directory #t) + (write-file + (make-pathname output-directory (pathname-strip-directory source-file) "html") + (populate-html-template (string-append "

    " source-file "

    " + "
    \n"
    +                                             (clean-html (git-file->string source-file))
    +                                             "
    "))))) + +(define (generate-source-files source-files-list) + (for-each (lambda (source-file) (generate-source-file source-file)) + source-files-list)) + +(define (generate-files-file files-list-page-path source-files-list) + (write-file + files-list-page-path + (populate-html-template (string-append "
      \n" + (generate-list-of-files source-files-list) + "
    \n")))) + +(define (generate-readme-file index-page-path) + (write-file + index-page-path + (populate-html-template (md->html (git-file->string "README.md"))))) + +(define (generate-repository-directory) + (if (directory-exists? *repository-directory*) + (begin (delete-directory *repository-directory* #t) + (create-directory *repository-directory* #t)) + (create-directory *repository-directory* #t))) + +(define (generate-html-files) + (let ((source-files-list (git-repository->paths-list))) + (generate-repository-directory) + (generate-readme-file (make-pathname *repository-directory* "index.html")) + (generate-files-file (make-pathname *repository-directory* "files.html") source-files-list) + (generate-source-files source-files-list))) + +(define (if-git-directory-generate-html-files) + (if (in-git-directory?) + (begin (set! *repository-name* (get-repository-name)) + (set! *repository-directory* (make-pathname WEB-DIRECTORY *repository-name*)) + (generate-html-files)) + (print "woops that's not a git directory"))) + +(define (main args) + (if (null? args) + (if-git-directory-generate-html-files) + (print "woops, i dont take args"))) + +(main (command-line-arguments)) + diff --git a/post-receive.sample b/post-receive.sample new file mode 100755 index 0000000..f6c3a81 --- /dev/null +++ b/post-receive.sample @@ -0,0 +1,11 @@ +#!/bin/sh + +# place this file in the 'hooks' directory of a bare git repository +# this assumes that repo2html is in your path + +export GIT_WWW=/var/www/git/ +export GIT_WWW_CLONE_URL=git://git.m455.casa +export GIT_WWW_TITLE=git.m455.casa +export GIT_WWW_DESCRIPTION="m455's git repositories" +export GIT_WWW_H1=git.m455.casa +repo2html