Skip to content

Commit fa4b879

Browse files
committed
upgrade: go back to go
1 parent cb61d53 commit fa4b879

File tree

5 files changed

+310
-54
lines changed

5 files changed

+310
-54
lines changed

upgrade/package.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
// +build !upgrade
2+
13
// Package upgrade is a dummy package to ensure package can be loaded
24
//
35
// This file is to avoid the following error:

upgrade/upgrade.go

Lines changed: 249 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,249 @@
1+
// +build !cgo
2+
// +build upgrade
3+
4+
package main
5+
6+
import (
7+
"archive/zip"
8+
"bufio"
9+
"bytes"
10+
"crypto/sha1"
11+
"encoding/hex"
12+
"errors"
13+
"fmt"
14+
"io"
15+
"io/ioutil"
16+
"log"
17+
"net/http"
18+
"os"
19+
"path/filepath"
20+
"strings"
21+
"time"
22+
23+
"github.com/PuerkitoBio/goquery"
24+
)
25+
26+
const buildFlags = "-DSQLITE_ENABLE_UPDATE_DELETE_LIMIT=1"
27+
28+
func main() {
29+
err := func() error {
30+
fmt.Println("Go-SQLite3 Upgrade Tool")
31+
32+
// Download Source
33+
source, hash, err := download("sqlite-src-")
34+
if err != nil {
35+
return fmt.Errorf("failed to download: sqlite-src; %v", err)
36+
}
37+
fmt.Printf("Download successful and verified hash %x\n", hash)
38+
39+
// Extract Source
40+
baseDir, err := extractZip(source)
41+
if baseDir != "" && !filepath.IsAbs(baseDir) {
42+
defer func() {
43+
fmt.Println("Cleaning up source: deleting", baseDir)
44+
os.RemoveAll(baseDir)
45+
}()
46+
}
47+
if err != nil {
48+
return fmt.Errorf("failed to extract source: %v", err)
49+
}
50+
fmt.Println("Extracted sqlite source to", baseDir)
51+
52+
// Build amalgamation files (OS-specific)
53+
fmt.Printf("Starting to generate amalgamation with build flags: %s\n", buildFlags)
54+
if err := buildAmalgamation(baseDir, buildFlags); err != nil {
55+
return fmt.Errorf("failed to build amalgamation: %v", err)
56+
}
57+
fmt.Println("SQLite3 amalgamation built")
58+
59+
// Patch bindings
60+
patchSource(baseDir, "sqlite3.c", "sqlite3-binding.c", "ext/userauth/userauth.c")
61+
patchSource(baseDir, "sqlite3.h", "sqlite3-binding.h", "ext/userauth/sqlite3userauth.h")
62+
patchSource(baseDir, "sqlite3ext.h", "sqlite3ext.h")
63+
64+
fmt.Println("Done patching amalgamation")
65+
return nil
66+
}()
67+
if err != nil {
68+
log.Fatal("Returned with error:", err)
69+
}
70+
}
71+
72+
func download(prefix string) (content, hash []byte, err error) {
73+
year := time.Now().Year()
74+
75+
site := "https://www.sqlite.org/download.html"
76+
//fmt.Printf("scraping %v\n", site)
77+
doc, err := goquery.NewDocument(site)
78+
if err != nil {
79+
return nil, nil, err
80+
}
81+
82+
url, hashString := "", ""
83+
doc.Find("tr").EachWithBreak(func(_ int, s *goquery.Selection) bool {
84+
found := false
85+
s.Find("a").Each(func(_ int, s *goquery.Selection) {
86+
if strings.HasPrefix(s.Text(), prefix) {
87+
found = true
88+
url = fmt.Sprintf("https://www.sqlite.org/%d/", year) + s.Text()
89+
}
90+
})
91+
if found {
92+
s.Find("td").Each(func(_ int, s *goquery.Selection) {
93+
text := s.Text()
94+
split := strings.Split(text, "(sha1: ")
95+
if len(split) < 2 {
96+
return
97+
}
98+
text = split[1]
99+
hashString = strings.Split(text, ")")[0]
100+
})
101+
}
102+
return !found
103+
})
104+
105+
targetHash, err := hex.DecodeString(hashString)
106+
if err != nil || len(targetHash) != sha1.Size {
107+
return nil, nil, fmt.Errorf("unable to find valid sha1 hash on sqlite.org: %q", hashString)
108+
}
109+
110+
if url == "" {
111+
return nil, nil, fmt.Errorf("unable to find prefix '%s' on sqlite.org", prefix)
112+
}
113+
114+
fmt.Printf("Downloading %v\n", url)
115+
resp, err := http.Get(url)
116+
if err != nil {
117+
return nil, nil, err
118+
}
119+
120+
// Ready Body Content
121+
shasum := sha1.New()
122+
content, err = ioutil.ReadAll(io.TeeReader(resp.Body, shasum))
123+
defer resp.Body.Close()
124+
if err != nil {
125+
return nil, nil, err
126+
}
127+
128+
computedHash := shasum.Sum(nil)
129+
if !bytes.Equal(targetHash, computedHash) {
130+
return nil, nil, fmt.Errorf("invalid hash of file downloaded from %q: got %x instead of %x", url, computedHash, targetHash)
131+
}
132+
133+
return content, computedHash, nil
134+
}
135+
136+
func extractZip(data []byte) (string, error) {
137+
zr, err := zip.NewReader(bytes.NewReader(data), int64(len(data)))
138+
if err != nil {
139+
return "", err
140+
}
141+
142+
if len(zr.File) == 0 {
143+
return "", errors.New("no files in zip archive")
144+
}
145+
if !zr.File[0].Mode().IsDir() {
146+
return "", errors.New("expecting base directory at the top of zip archive")
147+
}
148+
baseDir := zr.File[0].Name
149+
150+
for _, zf := range zr.File {
151+
if !strings.HasPrefix(zf.Name, baseDir) {
152+
return baseDir, fmt.Errorf("file %q in zip archive not in base directory %q", zf.Name, baseDir)
153+
}
154+
155+
if zf.Mode().IsDir() {
156+
if err := os.Mkdir(zf.Name, zf.Mode()); err != nil {
157+
return baseDir, err
158+
}
159+
continue
160+
}
161+
f, err := os.OpenFile(zf.Name, os.O_WRONLY|os.O_CREATE|os.O_EXCL, zf.Mode())
162+
if err != nil {
163+
return baseDir, err
164+
}
165+
if zf.UncompressedSize == 0 {
166+
continue
167+
}
168+
169+
zr, err := zf.Open()
170+
if err != nil {
171+
return baseDir, err
172+
}
173+
174+
_, err = io.Copy(f, zr)
175+
if err != nil {
176+
return baseDir, err
177+
}
178+
179+
if err := zr.Close(); err != nil {
180+
return baseDir, err
181+
}
182+
if err := f.Close(); err != nil {
183+
return baseDir, err
184+
}
185+
}
186+
187+
return baseDir, nil
188+
}
189+
190+
func patchSource(baseDir, src, dst string, extensions ...string) error {
191+
srcFile, err := os.Open(filepath.Join(baseDir, src))
192+
if err != nil {
193+
return err
194+
}
195+
defer srcFile.Close()
196+
197+
dstFile, err := os.Create(dst)
198+
if err != nil {
199+
return err
200+
}
201+
defer dstFile.Close()
202+
203+
_, err = io.WriteString(dstFile, "#ifndef USE_LIBSQLITE3\n")
204+
if err != nil {
205+
return err
206+
}
207+
scanner := bufio.NewScanner(srcFile)
208+
for scanner.Scan() {
209+
text := scanner.Text()
210+
if text == `#include "sqlite3.h"` {
211+
text = `#include "sqlite3-binding.h"`
212+
}
213+
_, err = fmt.Fprintln(dstFile, text)
214+
if err != nil {
215+
break
216+
}
217+
}
218+
err = scanner.Err()
219+
if err != nil {
220+
return err
221+
}
222+
_, err = io.WriteString(dstFile, "#else // USE_LIBSQLITE3\n// If users really want to link against the system sqlite3 we\n// need to make this file a noop.\n#endif\n")
223+
if err != nil {
224+
return err
225+
}
226+
227+
for _, ext := range extensions {
228+
ext = filepath.FromSlash(ext)
229+
fmt.Printf("Merging: %s into %s\n", ext, dst)
230+
231+
extFile, err := os.Open(filepath.Join(baseDir, ext))
232+
if err != nil {
233+
return err
234+
}
235+
_, err = io.Copy(dstFile, extFile)
236+
extFile.Close()
237+
if err != nil {
238+
return err
239+
}
240+
}
241+
242+
if err := dstFile.Close(); err != nil {
243+
return err
244+
}
245+
246+
fmt.Printf("Patched: %s -> %s\n", src, dst)
247+
248+
return nil
249+
}

upgrade/upgrade.sh

Lines changed: 0 additions & 54 deletions
This file was deleted.

upgrade/upgrade_unix.go

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// +build !cgo
2+
// +build upgrade
3+
// +build !windows
4+
5+
package main
6+
7+
import (
8+
"fmt"
9+
"os/exec"
10+
)
11+
12+
func buildAmalgamation(baseDir, buildFlags string) error {
13+
args := []string{"configure"}
14+
if buildFlags != "" {
15+
args = append(args, "CFLAGS="+buildFlags)
16+
}
17+
cmd := exec.Command("sh", args...)
18+
cmd.Dir = baseDir
19+
out, err := cmd.CombinedOutput()
20+
if err != nil {
21+
return fmt.Errorf("configure failed: %v\n\n%s", err, out)
22+
}
23+
fmt.Println("Ran configure successfully")
24+
25+
cmd = exec.Command("make", "sqlite3.c")
26+
cmd.Dir = baseDir
27+
out, err = cmd.CombinedOutput()
28+
if err != nil {
29+
return fmt.Errorf("make failed: %v\n\n%s", err, out)
30+
}
31+
fmt.Println("Ran make successfully")
32+
33+
return nil
34+
}

upgrade/upgrade_windows.go

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// +build !cgo
2+
// +build upgrade
3+
4+
package main
5+
6+
import (
7+
"fmt"
8+
"os/exec"
9+
)
10+
11+
func buildAmalgamation(baseDir, buildFlags string) error {
12+
args := []string{"/f", "Makefile.msc", "sqlite3.c"}
13+
if buildFlags != "" {
14+
args = append(args, "OPTS="+buildFlags)
15+
}
16+
cmd := exec.Command("nmake", args...)
17+
cmd.Dir = baseDir
18+
out, err := cmd.CombinedOutput()
19+
if err != nil {
20+
return fmt.Errorf("nmake failed: %v\n\n%s", err, out)
21+
}
22+
fmt.Println("Ran nmake successfully")
23+
24+
return nil
25+
}

0 commit comments

Comments
 (0)