Changes
diff --git a/main.go b/main.go
index 69ddf92..4c453b9 100644
--- a/main.go
+++ b/main.go
@@ -18,37 +18,126 @@ import (
"github.com/go-git/go-git/v5/plumbing/object"
)
+// CONFIG_FILE=".ht_git2html"
const configFile = ".ht_git2html"
+/*
+show_progress=1
+force_rebuild=0
+*/
+const showProgress = true
+const forceRebuild = false
+
+// TODO: add log.Debug
+/*
+ progress()
+ {
+ if test x"$show_progress" = x1
+ then
+ echo "$@"
+ fi
+ }
+*/
+
//go:embed config.tmpl
var tmpl string
+type options struct {
+ project string
+ repo string
+ link string
+ branches string
+ quiet bool
+ force bool
+}
+
+/*
+usage()
+
+ {
+ echo "Usage $0 [-prlbq] TARGET"
+ echo "Generate static HTML pages in TARGET for the specified git repository."
+ echo
+ echo " -p Project's name"
+ echo " -r Repository to clone from."
+ echo " -l Public repository link, e.g., 'http://host.org/project.git'"
+ echo " -b List of branches to process (default: all)."
+ echo " -q Be quiet."
+ echo " -f Force rebuilding of all pages."
+ exit $1
+ }
+*/
func main() {
- var p string
- var r string
- var l string
- var b string
- var q bool
- var f bool
-
- flag.StringVar(&p, "p", "My project", "Choose a project name")
- flag.StringVar(&r, "r", "/path/to/repo", "Repository to clone from")
- flag.StringVar(&l, "l", "http://host.org/project.git", "Public link to repo")
- flag.StringVar(&b, "b", "all", "List of branches")
- flag.BoolVar(&q, "q", false, "Be quiet")
- flag.BoolVar(&f, "f", false, "Force rebuilding of all pages")
+ /*
+ while getopts ":p:r:l:b:qf" opt
+ do
+ case $opt in
+ p)
+ PROJECT=$OPTARG
+ ;;
+ r)
+ # Directory containing the repository.
+ REPOSITORY=$OPTARG
+ ;;
+ l)
+ PUBLIC_REPOSITORY=$OPTARG
+ ;;
+ b)
+ BRANCHES=$OPTARG
+ ;;
+ q)
+ show_progress=0
+ ;;
+ f)
+ force_rebuild=1
+ ;;
+ \?)
+ echo "Invalid option: -$OPTARG" >&2
+ usage
+ ;;
+ esac
+ done
+ shift $(($OPTIND - 1))
+ */
+ opts := &options{}
+
+ flag.StringVar(&opts.project, "p", "My project", "Project's name")
+ flag.StringVar(&opts.repo, "r", "/path/to/repo", "Repository to clone from.")
+ flag.StringVar(&opts.link, "l", "http://host.org/project.git", "Public repository link, e.g., 'http://host.org/project.git'")
+ flag.StringVar(&opts.branches, "b", "all", "List of branches (default: all)")
+ flag.BoolVar(&opts.quiet, "q", false, "Be quiet.")
+ flag.BoolVar(&opts.force, "f", false, "Force rebuilding of all pages.")
flag.Parse()
- log.Printf("%v %v %v %v %v %v", p, r, l, b, q, f)
+ // TODO: print usage?
+ /*
+ if test $# -ne 1
+ then
+ usage 1
+ fi
+ */
+
+ log.Printf("+%v", opts)
args := os.Args
+ // TODO: check only one target
// if len(args) != 2 {
// log.Fatalf("jimmy: please specify a single target path")
// }
+ //# Where to create the html pages.
+ //TARGET="$1"
targetDir := args[len(args)-1]
+ //# Make sure TARGET is an absolute path.
+ /*
+ if test x"${TARGET%%/*}" != x
+ then
+ TARGET=$(pwd)/$TARGET
+ fi
+ */
+
if ok := filepath.IsAbs(targetDir); !ok {
cwd, err := os.Getwd()
@@ -59,11 +148,72 @@ func main() {
targetDir = filepath.Join(cwd, targetDir)
}
+ //# Make sure the target exists.
+ //mkdir -p "$TARGET"
+
// TODO: Look up more mode for 755 or 644.
if err := os.MkdirAll(targetDir, os.ModePerm); err != nil {
log.Fatalf("jimmy: unable to create target directory: %v", err)
}
+ //# Read the configuration file.
+ /*
+ if test -e "$TARGET/$CONFIG_FILE"
+ then
+ . "$TARGET/$CONFIG_FILE"
+ fi
+ */
+ // TODO: Read config file
+
+ // TODO: Check repository is required
+ /*
+ if test x"$REPOSITORY" = x
+ then
+ echo "-r required."
+ echo
+ usage 1
+ fi
+ */
+
+ writeConfigFile(targetDir, opts)
+
+ // TODO: check how to make -r arg mandatory
+ /*
+ if test ! -d "$REPOSITORY"
+ then
+ echo "Repository \"$REPOSITORY\" does not exists. Misconfiguration likely."
+ exit 1
+ fi
+ */
+
+ createDirectories(targetDir, opts.force)
+
+ setUpRepo(targetDir, opts)
+
+ setGitConfig()
+
+ cleanBranches := cleanUpBranches(opts.branches)
+
+ fetchBranches(cleanBranches)
+
+ writeIndex()
+
+ doTheRealWork()
+
+ writeIndexFooter()
+}
+
+func writeConfigFile(targetDir string, opts *options) {
+ /*
+ # The output version
+ CURRENT_TEMPLATE="$(sha1sum "$0")"
+ if test "x$CURRENT_TEMPLATE" != "x$TEMPLATE"
+ then
+ progress "Rebuilding all pages as output template changed."
+ force_rebuild=1
+ fi
+ TEMPLATE="$CURRENT_TEMPLATE"
+ */
configTmpl := template.Must(template.New("default").Parse(tmpl))
// TODO: Check file permissions are set to 0666.
@@ -76,10 +226,26 @@ func main() {
h := sha1.New()
+ // (spike): why did we do this step?
if _, err := io.Copy(h, outFile); err != nil {
log.Fatal(err)
}
+ /*
+ {
+ save()
+ {
+ # Prefer environment variables and arguments to the configuration file.
+ echo "$1=\"\${$1:-\"$2\"}\""
+ }
+ save "PROJECT" "$PROJECT"
+ save "REPOSITORY" "$REPOSITORY"
+ save "PUBLIC_REPOSITORY" "$PUBLIC_REPOSITORY"
+ save "TARGET" "$TARGET"
+ save "BRANCHES" "$BRANCHES"
+ save "TEMPLATE" "$TEMPLATE"
+ } > "$TARGET/$CONFIG_FILE"
+ */
configTmpl.Execute(outFile, struct {
Project string
Repository string
@@ -89,13 +255,38 @@ func main() {
// SHA1SUM
Template string
}{
- Project: p,
- Repository: r,
- PublicRepository: l,
+ Project: opts.project,
+ Repository: opts.repo,
+ PublicRepository: opts.link,
Target: targetDir,
- Branches: b,
+ Branches: opts.branches,
Template: hex.EncodeToString(h.Sum(nil)),
})
+}
+
+func createDirectories(targetDir string, force bool) {
+ //# Ensure that some directories we need exist.
+ /*
+ if test x"$force_rebuild" = x1
+ then
+ rm -rf "$TARGET/objects" "$TARGET/commits"
+ fi
+
+ if test ! -d "$TARGET/objects"
+ then
+ mkdir "$TARGET/objects"
+ fi
+
+ if test ! -e "$TARGET/commits"
+ then
+ mkdir "$TARGET/commits"
+ fi
+
+ if test ! -e "$TARGET/branches"
+ then
+ mkdir "$TARGET/branches"
+ fi
+ */
// Repository
dirs := []string{"branches", "commits", "objects"}
@@ -104,7 +295,7 @@ func main() {
d := filepath.Join(targetDir, dir)
// Clear existing dirs if force true.
- if f && dir != "branches" {
+ if force && dir != "branches" {
if err := os.RemoveAll(d); err != nil {
log.Printf("jimmy: unable to remove directory: %v", err)
}
@@ -114,65 +305,523 @@ func main() {
log.Printf("jimmy: unable to create directory: %v", err)
}
}
+}
+func setUpRepo(targetDir string, opts *options) {
var pathError *fs.PathError
- repo := filepath.Join(targetDir, "repository")
+ repoPath := filepath.Join(targetDir, "repository")
- _, err = os.Stat(repo)
+ _, err := os.Stat(repoPath)
if errors.As(err, &pathError) {
- ro, err := git.PlainClone(repo, false, &git.CloneOptions{
- URL: r,
+ localRepo, err := git.PlainClone(repoPath, false, &git.CloneOptions{
+ URL: opts.repo,
Progress: os.Stdout,
})
- co, err := ro.CommitObjects()
+ commitObjects, err := localRepo.CommitObjects()
if err != nil {
log.Printf("%v", err)
}
- co.ForEach(func(c *object.Commit) error {
+ commitObjects.ForEach(func(c *object.Commit) error {
log.Print(c)
return nil
})
- branches, err := ro.Branches()
+ localBranches, err := localRepo.Branches()
if err != nil {
log.Printf("%v", err)
}
- branch, err := branches.Next()
+ branch, err := localBranches.Next()
if err != nil {
- log.Printf("jimmy: failed to clone repo: %v", err)
+ log.Printf("jimmy: failed to list branches: %v", err)
}
ref := plumbing.NewHashReference(branch.Name(), branch.Hash())
if err != nil {
- log.Printf("jimmy: failed to clone repo: %v", err)
+ log.Printf("jimmy: failed to create ref: %v", err)
}
- w, err := ro.Worktree()
+ workTree, err := localRepo.Worktree()
if err != nil {
- log.Printf("jimmy: failed to clone repo: %v", err)
+ log.Printf("jimmy: failed to open worktree: %v", err)
}
- err = w.Checkout(&git.CheckoutOptions{
+ err = workTree.Checkout(&git.CheckoutOptions{
Hash: ref.Hash(),
})
if err != nil {
- log.Printf("jimmy: failed to clone repo: %v", err)
+ log.Printf("jimmy: failed to checkout detached HEAD: %v", err)
}
- err = ro.Storer.RemoveReference(ref.Name())
+ err = localRepo.Storer.RemoveReference(ref.Name())
if err != nil {
- log.Printf("jimmy: failed to clone repo: %v", err)
+ log.Printf("jimmy: failed to delete branch: %v", err)
}
}
}
+
+// TODO: implement!
+func setGitConfig() {
+ /*
+ # git merge fails if there are not set. Fake them.
+ git config user.email "git2html@git2html"
+ git config user.name "git2html"
+ */
+}
+
+// TODO: implement!
+func cleanUpBranches(branches string) []string {
+ /*
+ if test x"$BRANCHES" = x
+ then
+ # Strip the start of lines of the form 'origin/HEAD -> origin/master'
+ BRANCHES=$(git branch --no-color -r \
+ | sed 's#.*->##; s#^ *origin/##;')
+ fi
+
+ first=""
+ # Ignore 'origin/HEAD -> origin/master'
+ for branch in ${BRANCHES:-$(git branch --no-color -r \
+ | sed 's#.*->.*##;
+ s#^ *origin/##;
+ s#^ *HEAD *$##;')}
+ do
+ first="$branch"
+ break
+ done
+
+ # Due to branch aliases (a la origin/HEAD), a branch might be listed
+ # multiple times. Eliminate this possibility.
+ BRANCHES=$(for branch in $BRANCHES
+ do
+ echo "$branch"
+ done | sort | uniq)
+ */
+ return []string{}
+}
+
+// TODO: implement!
+func fetchBranches(branches []string) {
+ /*
+ for branch in $BRANCHES
+ do
+ # Suppress already up to date status messages, but don't use grep -v
+ # as that returns 1 if there is no output and causes the script to
+ # abort.
+ git fetch --force origin "refs/heads/${branch}:refs/origin/${branch}" \
+ | gawk '/^Already up-to-date[.]$/ { skip=1; }
+ { if (! skip) print; skip=0 }'
+ done
+ git checkout "origin/$first"
+ }
+
+ # For each branch and each commit create and extract an archive of the form
+ # $TARGET/commits/$commit
+ #
+ # and a link:
+ #
+ # $TARGET/branches/$commit -> $TARGET/commits/$commit
+
+ # Count the number of branch we want to process to improve reporting.
+ bcount=0
+ for branch in $BRANCHES
+ do
+ let ++bcount
+ done
+ */
+}
+
+// TODO: implement!
+func writeIndex() {
+ /*
+ INDEX="$TARGET/index.html"
+
+ {
+ html_header
+
+ if test -e "$REPOSITORY/description"
+ then
+ echo "<h2>Description</h2>"
+ cat "$REPOSITORY/description"
+ fi
+
+ echo "<h2>Repository</h2>"
+ if test x"$PUBLIC_REPOSITORY" != x
+ then
+ echo "Clone this repository using:" \
+ "<pre>" \
+ " git clone $PUBLIC_REPOSITORY" \
+ "</pre>"
+ fi
+
+ echo "<h2>Branches</h2>" \
+ "<ul>"
+ } > "$INDEX"
+
+ */
+}
+
+// TODO: implement!
+func doTheRealWork() {
+ /*
+ b=0
+ for branch in $BRANCHES
+ do
+ let ++b
+
+ cd "$TARGET/repository"
+
+ COMMITS=$(mktemp)
+ git rev-list --graph "origin/$branch" > $COMMITS
+
+ # Count the number of commits on this branch to improve reporting.
+ ccount=$(egrep '[0-9a-f]' < $COMMITS | wc -l)
+
+ progress "Branch $branch ($b/$bcount): processing ($ccount commits)."
+
+ BRANCH_INDEX="$TARGET/branches/$branch.html"
+
+ c=0
+ while read -r commitline
+ do
+ # See http://www.itnewb.com/unicode
+ graph=$(echo "$commitline" \
+ | sed 's/ [0-9a-f]*$//; s/|/\┃/g; s/[*]/\●/g;
+ s/[\]/\⬊/g; s/\//\⬋/g;')
+ */
+ // commit=$(echo "$commitline" | sed 's/^[^0-9a-f]*//')
+ /*
+ if test x"$commit" = x
+ then
+ # This is just a bit of graph. Add it to the branch's
+ # index.html and then go to the next commit.
+ echo "<tr><td valign=\"middle\"><pre>$graph</pre></td><td></td><td></td><td></td></tr>" \
+ >> "$BRANCH_INDEX"
+ continue
+ fi
+
+ let ++c
+ progress "Commit $commit ($c/$ccount): processing."
+
+ # Extract metadata about this commit.
+ metadata=$(git log -n 1 --pretty=raw $commit \
+ | sed 's#<#\<#g; s#>#\>#g; ')
+ parent=$(echo "$metadata" \
+ | gawk '/^parent / { $1=""; sub (" ", ""); print $0 }')
+ author=$(echo "$metadata" \
+ | gawk '/^author / { NF=NF-2; $1=""; sub(" ", ""); print $0 }')
+ date=$(echo "$metadata" | gawk '/^author / { print $(NF=NF-1); }')
+ date=$(date -u -d "1970-01-01 $date sec")
+ log=$(echo "$metadata" | gawk '/^ / { if (!done) print $0; done=1; }')
+ loglong=$(echo "$metadata" | gawk '/^ / { print $0; }')
+
+ if test "$c" = "1"
+ then
+ # This commit is the current head of the branch. Update the
+ # branch's link, but don't use ln -sf: because the symlink is to
+ # a directory, the symlink won't be replaced; instead, the new
+ # link will be created in the existing symlink's target
+ # directory:
+ #
+ # $ mkdir foo
+ # $ ln -s foo bar
+ # $ ln -s baz bar
+ # $ ls -ld bar bar/baz
+ # lrwxrwxrwx 1 neal neal 3 Aug 3 09:14 bar -> foo
+ # lrwxrwxrwx 1 neal neal 3 Aug 3 09:14 bar/baz -> baz
+ rm -f "$TARGET/branches/$branch"
+ ln -s "../commits/$commit" "$TARGET/branches/$branch"
+
+ # Update the project's index.html and the branch's index.html.
+ echo "<li><a href=\"branches/$branch.html\">$branch</a>: " \
+ "<b>$log</b> $author <i>$date</i>" >> "$INDEX"
+
+ {
+ html_header "Branch: $branch" ".."
+ echo "<p><a href=\"$branch/index.html\">HEAD</a>"
+ echo "<p><table>"
+ } > "$BRANCH_INDEX"
+ fi
+
+ # Add this commit to the branch's index.html.
+ echo "<tr><td valign=\"middle\"><pre>$graph</pre></td><td><a href=\"../commits/$commit/index.html\">$log</a></td><td>$author</td><td><i>$date</i></td></tr>" \
+ >> "$BRANCH_INDEX"
+
+
+ # Commits don't change. If the directory already exists, it is up
+ # to date and we can save some work.
+ COMMIT_BASE="$TARGET/commits/$commit"
+ if test -e "$COMMIT_BASE"
+ then
+ progress "Commit $commit ($c/$ccount): already processed."
+ continue
+ fi
+
+ mkdir "$COMMIT_BASE"
+
+ # Get the list of files in this commit.
+ FILES=$(mktemp)
+ git ls-tree -r "$commit" > "$FILES"
+
+ # Create the commit's index.html: the metadata, a summary of the changes
+ # and a list of all the files.
+ COMMIT_INDEX="$COMMIT_BASE/index.html"
+ {
+ html_header "Commit: $commit" "../.."
+
+ # The metadata.
+ echo "<h2>Branch: <a href=\"../../branches/$branch.html\">$branch</a></h2>" \
+ "<p>Author: $author" \
+ "<br>Date: $date" \
+ "<br>Commit: $commit"
+ for p in $parent
+ do
+ echo "<br>Parent: <a href=\"../../commits/$p/index.html\">$p</a>" \
+ " (<a href=\"../../commits/$commit/diff-to-$p.html\">diff to parent</a>)"
+ done
+ echo "<br>Log message:" \
+ "<p><pre>$loglong</pre>"
+ for p in $parent
+ do
+ echo "<br>Diff Stat to $p:" \
+ "<blockquote><pre>"
+ git diff --stat $p..$commit \
+ | gawk \
+ '{ if (last_line) print last_line;
+ last_line_raw=$0;
+ $1=sprintf("<a href=\"%s.raw.html\">%s</a>" \
+ " (<a href=\"../../commits/'"$p"'/%s.raw.html\">old</a>)" \
+ "%*s" \
+ "(<a href=\"diff-to-'"$p"'.html#%s\">diff</a>)",
+ $1, $1, $1, 60 - length ($1), " ", $1);
+ last_line=$0; }
+ END { print last_line_raw; }'
+ echo "</pre></blockquote>"
+ done
+ echo "<p>Files:" \
+ "<ul>"
+
+ # The list of files as a hierarchy. Sort them so that within a
+ # directory, files preceed sub-directories
+ sed 's/\([^ \t]\+[ \t]\)\{3\}//;
+ */
+ // s#^#/#; s#/\([^/]*/\)#/1\1#; s#/\([^/]*\)$#/0\1#;' \
+ /*
+ < "$FILES" \
+ | sort | sed 's#/[01]#/#g; s#^/##' \
+ | gawk '
+ function spaces(l) {
+ for (space = 1; space <= l; space ++) { printf (" "); }
+ }
+ function max(a, b) { if (a > b) { return a; } return b; }
+ function min(a, b) { if (a < b) { return a; } return b; }
+ function join(array, sep, i, s) {
+ s="";
+ for (i in array) {
+ if (s == "")
+ s = array[i];
+ else
+ s = s sep array[i];
+ }
+ return s;
+ }
+ BEGIN {
+ current_components[1] = "";
+ delete current_components[1];
+ }
+ {
+ file=$0;
+ split(file, components, "/")
+ # Remove the file. Keep the directories.
+ file=components[length(components)]
+ delete components[length(components)];
+
+ # See if a path component changed.
+ for (i = 1;
+ i <= min(length(components), length(current_components));
+ i ++)
+ {
+ if (current_components[i] != components[i])
+ # It did.
+ break
+ }
+ # i-1 is the last common component. The rest from the
+ # current_component stack.
+ last=length(current_components);
+ for (j = last; j >= i; j --)
+ {
+ spaces(j);
+ printf ("</ul> <!-- %s -->\n", current_components[j]);
+ delete current_components[j];
+ }
+
+ # If there are new path components push them on the
+ # current_component stack.
+ for (; i <= length(components); i ++)
+ {
+ current_components[i] = components[i];
+ spaces(i);
+ printf("<li><a name=\"files:%s\">%s</a>\n",
+ join(current_components, "/"), components[i]);
+ spaces(i);
+ printf("<ul>\n");
+ }
+
+ spaces(length(current_components))
+ printf ("<li><a name=\"files:%s\" href=\"%s.raw.html\">%s</a>\n",
+ $0, $0, file);
+ printf (" (<a href=\"%s\">raw</a>)\n", $0, file);
+ }
+ END {
+ for (i = length(current_components); j >= 1; j --)
+ {
+ spaces(j);
+ printf ("</ul> <!-- %s -->\n", current_components[j]);
+ delete current_components[j];
+ }
+ }'
+
+ echo "</ul>"
+ html_footer
+ } > "$COMMIT_INDEX"
+
+ # Create the commit's diff-to-parent.html file.
+ for p in $parent
+ do
+ {
+ */
+ // html_header "diff $(echo $commit | sed 's/^\(.\{8\}\).*/\1/') $(echo $p | sed 's/^\(.\{8\}\).*/\1/')" "../.."
+ /*
+ echo "<h2>Branch: <a href=\"../../branches/$branch.html\">$branch</a></h2>" \
+ "<h3>Commit: <a href=\"index.html\">$commit</a></h3>" \
+ "<p>Author: $author" \
+ "<br>Date: $date" \
+ "<br>Parent: <a href=\"../$p/index.html\">$p</a>" \
+ "<br>Log message:" \
+ "<p><pre>$loglong</pre>" \
+ "<p>" \
+ "<pre>"
+ git diff -p $p..$commit \
+ | sed 's#<#\<#g; s#>#\>#g;
+ s#^\(diff --git a/\)\([^ ]\+\)#\1<a name="\2">\2</a>#;
+ s#^\(\(---\|+++\|index\|diff\|deleted\|new\) .\+\)$#<b>\1</b>#;
+ s#^\(@@ .\+\)$#<font color=\"blue\">\1</font>#;
+ s#^\(-.*\)$#<font color=\"red\">\1</font>#;
+ s#^\(+.*\)$#<font color=\"green\">\1</font>#;' \
+ | gawk '{ ++line; printf("%5d: %s\n", line, $0); }'
+ echo "</pre>"
+ html_footer
+ } > "$COMMIT_BASE/diff-to-$p.html"
+ done
+
+
+ # For each file in the commit, ensure the object exists.
+ while read -r line
+ do
+ file_base=$(echo "$line" | gawk '{ print $4 }')
+ file="$TARGET/commits/$commit/$file_base"
+ sha=$(echo "$line" | gawk '{ print $3 }')
+
+ object_dir="$TARGET/objects/"$(echo "$sha" \
+ | sed 's#^\([a-f0-9]\{2\}\).*#\1#')
+ object="$object_dir/$sha"
+
+ if test ! -e "$object"
+ then
+ # File does not yet exists in the object repository.
+ # Create it.
+ if test ! -d "$object_dir"
+ then
+ mkdir "$object_dir"
+ fi
+
+ # The object's file should not be commit or branch specific:
+ # the same html is shared among all files with the same
+ # content.
+ {
+ html_header "$sha"
+ echo "<pre>"
+ git show "$sha" \
+ | sed 's#<#\<#g; s#>#\>#g; ' \
+ | gawk '{ ++line; printf("%6d: %s\n", line, $0); }'
+ echo "</pre>"
+ html_footer
+ } > "$object"
+ fi
+
+ # Create a hard link to the formatted file in the object repository.
+ mkdir -p $(dirname "$file")
+ ln "$object" "$file.raw.html"
+
+ # Create a hard link to the raw file.
+ raw_filename="raw/$(echo "$sha" | sed 's/^\(..\)/\1\//')"
+ if ! test -e "$raw_filename"
+ then
+ mkdir -p "$(dirname "$raw_filename")"
+ git cat-file blob "$sha" > $raw_filename
+ fi
+ ln "$raw_filename" "$file"
+ done <"$FILES"
+ rm -f "$FILES"
+ done <$COMMITS
+ rm -f $COMMITS
+
+ {
+ echo "</table>"
+ html_footer
+ } >> "$BRANCH_INDEX"
+ done
+ */
+}
+
+// TODO: implement!
+func writeIndexFooter() {
+ /*
+ {
+ echo "</ul>"
+ html_footer
+ } >> "$INDEX"
+ */
+}
+
+// TODO: implement!
+func htmlHeader() {
+ /*
+ html_header()
+ {
+ title="$1"
+ top_level="$2"
+
+ if test x"$PROJECT" != x -a x"$title" != x
+ then
+ # Title is not the empty string. Prefix it with ": "
+ title=": $title"
+ fi
+
+ echo "<html><head><title>$PROJECT$title</title></head>" \
+ "<body>" \
+ "<h1><a href=\"$top_level/index.html\">$PROJECT</a>$title</h1>"
+ }
+ */
+}
+
+func htmlFooter() {
+ /*
+ html_footer()
+ {
+ echo "<hr>" \
+ "Generated by" \
+ "<a href=\"http://hssl.cs.jhu.edu/~neal/git2html\">git2html</a>."
+ }
+ */
+}