Compare commits
5 Commits
b006333035
...
83c8f63fe3
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
83c8f63fe3 | ||
|
|
aaeb3f1930 | ||
|
|
6604c26204 | ||
|
|
ba6d6483e0 | ||
|
|
58cafcfaa3 |
@@ -6,6 +6,7 @@ import (
|
|||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
"io/fs"
|
||||||
"log"
|
"log"
|
||||||
"maps"
|
"maps"
|
||||||
"net/http"
|
"net/http"
|
||||||
@@ -29,9 +30,13 @@ import (
|
|||||||
var _staticFileDir embed.FS
|
var _staticFileDir embed.FS
|
||||||
var publicHandler = func() http.Handler {
|
var publicHandler = func() http.Handler {
|
||||||
if os.Getenv("DEBUG") != "" {
|
if os.Getenv("DEBUG") != "" {
|
||||||
return http.FileServer(http.Dir("./http"))
|
return http.FileServer(http.Dir("./http/public"))
|
||||||
}
|
}
|
||||||
return http.FileServer(http.FS(_staticFileDir))
|
sub, err := fs.Sub(_staticFileDir, "public")
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
return http.FileServer(http.FS(sub))
|
||||||
}()
|
}()
|
||||||
|
|
||||||
func Main() {
|
func Main() {
|
||||||
|
|||||||
3090
cmd/http/moolah.dat
3090
cmd/http/moolah.dat
File diff suppressed because it is too large
Load Diff
1
cmd/http/moolah.dat
Symbolic link
1
cmd/http/moolah.dat
Symbolic link
@@ -0,0 +1 @@
|
|||||||
|
moolah.dat.real
|
||||||
3091
cmd/http/moolah.dat.real
Normal file
3091
cmd/http/moolah.dat.real
Normal file
File diff suppressed because it is too large
Load Diff
@@ -16,8 +16,8 @@
|
|||||||
<body style="height: 100%;" onload="init();">
|
<body style="height: 100%;" onload="init();">
|
||||||
<h1>Moolah2 Hub</h1>
|
<h1>Moolah2 Hub</h1>
|
||||||
<ul style="line-height: 3em;">
|
<ul style="line-height: 3em;">
|
||||||
<li><a href="/public/transactions.html">Transactions on Shared Chase</a></li>
|
<li><a href="/transactions.html">Transactions on Shared Chase</a></li>
|
||||||
<li><a href="/public/explore.html">Explore Bel's Money</a></li>
|
<li><a href="/explore.html">Explore Bel's Money</a></li>
|
||||||
<li><a href="/api/bal?x=y&mode=bal&likeName=AssetAccount&chart=stack&predictionMonths=120&bpi=true&zoomStart=YYYY-MM&prediction=interest=AssetAccount:Cash%20\$%200.02&prediction=contributions=AssetAccount:Bonds%20$%201875&prediction=interest=AssetAccount:Monthly%20\$%200.03&prediction=contributions=AssetAccount:Monthly%20$%202500&predictFixedGrowth=VBTLX=0.02&predictFixedGrowth=GLD=0.02&predictFixedGrowth=FXAIX=0.03&predictFixedGrowth=FSPSX=0.03&whatIf=AssetAccount:Cash%20$%20-.10000&=">Project Bel's Net Worth</a></li>
|
<li><a href="/api/bal?x=y&mode=bal&likeName=AssetAccount&chart=stack&predictionMonths=120&bpi=true&zoomStart=YYYY-MM&prediction=interest=AssetAccount:Cash%20\$%200.02&prediction=contributions=AssetAccount:Bonds%20$%201875&prediction=interest=AssetAccount:Monthly%20\$%200.03&prediction=contributions=AssetAccount:Monthly%20$%202500&predictFixedGrowth=VBTLX=0.02&predictFixedGrowth=GLD=0.02&predictFixedGrowth=FXAIX=0.03&predictFixedGrowth=FSPSX=0.03&whatIf=AssetAccount:Cash%20$%20-.10000&=">Project Bel's Net Worth</a></li>
|
||||||
<li><a href="/api/reg?x=y&mode=reg&likeName=Withdrawal:&chart=stack&predictionMonths=3&bpi=false&zoomStart=YYYY-MM&prediction=autoContributions=&predictFixedGrowth=VBTLX=0&whatIf=AssetAccount:Cash%20$%20-.10000&=">Expect Bel's Expenses</a></li>
|
<li><a href="/api/reg?x=y&mode=reg&likeName=Withdrawal:&chart=stack&predictionMonths=3&bpi=false&zoomStart=YYYY-MM&prediction=autoContributions=&predictFixedGrowth=VBTLX=0&whatIf=AssetAccount:Cash%20$%20-.10000&=">Expect Bel's Expenses</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|||||||
@@ -17,7 +17,7 @@
|
|||||||
}
|
}
|
||||||
function callback(responseBody, responseStatus) {
|
function callback(responseBody, responseStatus) {
|
||||||
}
|
}
|
||||||
var f = String(window.location).split("/public/transactions.html")[1]
|
var f = String(window.location).split("/transactions.html")[1]
|
||||||
if (!f) {
|
if (!f) {
|
||||||
f = "/moolah.dat"
|
f = "/moolah.dat"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,26 +36,51 @@ func (files Files) TempGetLastNLines(n int) ([]string, error) {
|
|||||||
|
|
||||||
func (files Files) TempSetLastNLines(n int, lines []string) error {
|
func (files Files) TempSetLastNLines(n int, lines []string) error {
|
||||||
p := files.paths()[0]
|
p := files.paths()[0]
|
||||||
w, err := ioutil.TempFile(os.TempDir(), path.Base(p))
|
|
||||||
|
newFile, err := func() (string, error) {
|
||||||
|
w, err := ioutil.TempFile(os.TempDir(), path.Base(p))
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
defer w.Close()
|
||||||
|
|
||||||
|
r, err := os.Open(p)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
defer r.Close()
|
||||||
|
|
||||||
|
if _, err := peekLastNLines(w, bufio.NewReader(r), n); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
for i := range lines {
|
||||||
|
if _, err := fmt.Fprintln(w, lines[i]); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if err := w.Close(); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return w.Name(), nil
|
||||||
|
}()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
defer w.Close()
|
|
||||||
|
|
||||||
r, err := os.Open(p)
|
r, err := os.Open(newFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
defer r.Close()
|
defer r.Close()
|
||||||
|
|
||||||
if _, err := peekLastNLines(w, bufio.NewReader(r), n); err != nil {
|
w, err := os.Create(p)
|
||||||
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
for i := range lines {
|
defer w.Close()
|
||||||
fmt.Fprintln(w, lines[i])
|
|
||||||
}
|
|
||||||
|
|
||||||
return os.Rename(w.Name(), p)
|
_, err = io.Copy(w, r)
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func peekLastNLines(w io.Writer, r *bufio.Reader, n int) ([]string, error) {
|
func peekLastNLines(w io.Writer, r *bufio.Reader, n int) ([]string, error) {
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package ledger
|
package ledger
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
@@ -401,22 +402,39 @@ func TestFilesTempSetLastNLines(t *testing.T) {
|
|||||||
c := d
|
c := d
|
||||||
t.Run(name, func(t *testing.T) {
|
t.Run(name, func(t *testing.T) {
|
||||||
p := path.Join(t.TempDir(), base64.URLEncoding.EncodeToString([]byte(t.Name())))
|
p := path.Join(t.TempDir(), base64.URLEncoding.EncodeToString([]byte(t.Name())))
|
||||||
os.WriteFile(p, []byte(c.given), os.ModePerm)
|
realp := p + ".real"
|
||||||
files := Files([]string{p})
|
|
||||||
if err := files.TempSetLastNLines(c.n, c.input); err != nil {
|
os.WriteFile(realp, []byte(c.given), os.ModePerm)
|
||||||
s := err.Error()
|
if err := os.Symlink(realp, p); err != nil {
|
||||||
if _, err := os.Stat(s); err == nil {
|
|
||||||
got, _ := os.ReadFile(s)
|
|
||||||
if string(got) != c.want {
|
|
||||||
t.Errorf("want\n%s, got\n%s", c.want, got)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
if stat, err := os.Lstat(p); err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
} else if stat.Mode().IsRegular() {
|
||||||
|
t.Error("p is already a regular file")
|
||||||
|
}
|
||||||
|
|
||||||
|
files := Files([]string{p})
|
||||||
|
if err := files.TempSetLastNLines(c.n, c.input); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
got, _ := os.ReadFile(p)
|
got, _ := os.ReadFile(p)
|
||||||
if string(got) != c.want {
|
if string(got) != c.want {
|
||||||
t.Errorf("want\n%s, got\n%s", c.want, got)
|
t.Errorf("want\n%s, got\n%s", c.want, got)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
realb, _ := os.ReadFile(realp)
|
||||||
|
b, _ := os.ReadFile(realp)
|
||||||
|
if !bytes.Equal(b, realb) {
|
||||||
|
t.Errorf("%s no longer links to %s", p, realp)
|
||||||
|
}
|
||||||
|
|
||||||
|
if stat, err := os.Lstat(p); err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
} else if stat.Mode().IsRegular() {
|
||||||
|
t.Error("p is now a regular file")
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user