zenbook migration

This commit is contained in:
2026-02-08 10:25:39 +01:00
commit 84b8735385
178 changed files with 5350 additions and 0 deletions
+6
View File
@@ -0,0 +1,6 @@
<component name="InspectionProjectProfileManager">
<profile version="1.0">
<option name="myName" value="Project Default" />
<inspection_tool class="Eslint" enabled="true" level="WARNING" enabled_by_default="true" />
</profile>
</component>
+8
View File
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/zcli-playground.iml" filepath="$PROJECT_DIR$/.idea/zcli-playground.iml" />
</modules>
</component>
</project>
Generated
+4
View File
@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings" defaultProject="true" />
</project>
+4
View File
@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="PropertiesComponent">{}</component>
</project>
+10
View File
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="WEB_MODULE" version="4">
<component name="Go" enabled="true" />
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$" />
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" name="typesense" level="application" />
</component>
</module>
+3
View File
@@ -0,0 +1,3 @@
module github.com/tikinang/cdn
go 1.24.0
View File
+14
View File
@@ -0,0 +1,14 @@
<!-- directly served by the object storage (S3) origin -->
<img src='https://storage-prg1.zerops.io/my-bucket/path/to/my-image.png'/>
<img src='{{ osGetEnv "storage_cdnUrl" }}/path/to/my-image.png'/>
<!-- served cached S3 object close to users by the "storage" CDN -->
<img src='https://storage.cdn.zerops.app/my-bucket/path/to/my-image.png'/>
<img src='{{ osGetEnv "storage_apiUrl" }}/{{ osGetEnv "storage_bucketName" }}/path/to/my-image.png'/>
<!-- directly served by your app -->
<img src='/static/path/to/my-image.png'/>
<!-- served cached static content close to users by the "url" CDN -->
<img src='https://url.cdn.zerops.app/my.domain.com/static/path/to/my-image.png'/>
<img src='{{ osGetEnv "zeropsCdnUrl" }}/my.domain.com/static/path/to/my-image.png'/>
+32
View File
@@ -0,0 +1,32 @@
<!DOCTYPE html>
<html>
<head>
<title>Fetch Image Example</title>
</head>
<body>
<h1>Image loaded with fetch</h1>
<div id="image-container"></div>
<img height="128" src="https://app.zerops.matejpavlicek.cz/static/gopher-profilovka.png" alt="gopher"/>
<img height="128" src="https://nginx-fd5.prg1.zerops.app/static/gopher-profilovka.png" alt="gopher-with-cors"/>
<script>
fetch('https://cz-url.cdn.zerops.app/nginx.zerops.matejpavlicek.cz/static/gopher-profilovka-2.png')
.then(response => response.blob())
.then(blob => {
const objectURL = URL.createObjectURL(blob);
const img = document.createElement('img');
img.height = 128;
img.src = objectURL;
document.getElementById('image-container').appendChild(img);
img.onload = () => {
URL.revokeObjectURL(objectURL);
};
})
.catch(error => {
console.error('Error:', error);
});
</script>
</body>
</html>
+48
View File
@@ -0,0 +1,48 @@
<html>
<head>
<title>CDN TEST</title>
</head>
<body>
<h1>TEST</h1>
<p>
direct static
<img height="128" src="static/gopher_profilovka.png" alt="gopher"/>
</p>
<p>
cdn static
<img height="128" src="https://static.cdn.zerops.app/nginx.zerops.matejpavlicek.cz/static/gopher_profilovka.png" alt="gopher"/>
</p>
<p>
direct s3
<img height="128" src="https://storage-prg1.zerops.io/4gh42-bucket1/gopher_profilovka.png" alt="gopher"/>
</p>
<p>
cdn s3
<img height="128" src="https://storage.cdn.zerops.app/4gh42-bucket1/gopher_profilovka.png" alt="gopher"/>
</p>
<p>
fetch static
<div id="image-container"></div>
</p>
<script>
fetch('https://static.cdn.zerops.app/nginx.zerops.matejpavlicek.cz/static/gopher_profilovka.png')
.then(response => response.blob())
.then(blob => {
const objectURL = URL.createObjectURL(blob);
const img = document.createElement('img');
img.height = 128;
img.src = objectURL;
img.alt = 'gopher'
document.getElementById('image-container').appendChild(img);
img.onload = () => {
URL.revokeObjectURL(objectURL);
};
})
.catch(error => {
console.error('Error:', error);
});
</script>
</body>
</html>
+14
View File
@@ -0,0 +1,14 @@
package main
import (
"fmt"
"net/http"
)
func main() {
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
_, _ = fmt.Fprintln(w, "OK")
})
_ = http.ListenAndServe(":8080", nil)
}
+32
View File
@@ -0,0 +1,32 @@
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name _;
root /var/www;
location ^~ /.git {
deny all;
return 404;
}
location / {
try_files $uri $uri/ /index.html;
}
location /static/ {
try_files $uri $uri/ =404;
add_header 'Access-Control-Allow-Origin' '*' always;
add_header 'Access-Control-Allow-Methods' '*' always;
add_header 'Access-Control-Allow-Headers' '*' always;
add_header 'Access-Control-Expose-Headers' '*' always;
if ($request_method = 'OPTIONS') {
return 204;
}
}
access_log syslog:server=unix:/dev/log,facility=local1,tag=nginx,severity=info default_short;
error_log syslog:server=unix:/dev/log,facility=local1,tag=nginx,severity=error;
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 271 KiB

+1
View File
@@ -0,0 +1 @@
HELLO
+11
View File
@@ -0,0 +1,11 @@
services:
- hostname: app
type: alpine@3.20
maxContainers: 1
- hostname: static
type: static@latest
maxContainers: 1
- hostname: nginx
type: nginx@latest
maxContainers: 1
startWithoutCode: true
+49
View File
@@ -0,0 +1,49 @@
zerops:
- setup: app
build:
os: alpine
base:
- go@1
buildCommands:
- go build -o app main.go
cache: true
deployFiles:
- app
run:
os: alpine
base: alpine@latest
ports:
- port: 8080
httpSupport: true
start: ./app
- setup: static
build:
deployFiles:
- index.html
- static/
run:
os: alpine
base: static@latest
ports:
- port: 80
httpSupport: true
- setup: nginx
build:
deployFiles:
- index.html
- static/
- nginx.conf
addToRunPrepare:
-
run:
os: alpine
base: nginx@latest
prepareCommands:
- sudo apk update
- sudo apk add vim
ports:
- port: 80
httpSupport: true
siteConfigPath: nginx.conf
+24
View File
@@ -0,0 +1,24 @@
module local
go 1.23.0
require github.com/ClickHouse/clickhouse-go/v2 v2.34.0
require (
filippo.io/edwards25519 v1.1.0 // indirect
github.com/ClickHouse/ch-go v0.65.1 // indirect
github.com/andybalholm/brotli v1.1.1 // indirect
github.com/go-faster/city v1.0.1 // indirect
github.com/go-faster/errors v0.7.1 // indirect
github.com/go-sql-driver/mysql v1.9.2 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/klauspost/compress v1.18.0 // indirect
github.com/paulmach/orb v0.11.1 // indirect
github.com/pierrec/lz4/v4 v4.1.22 // indirect
github.com/segmentio/asm v1.2.0 // indirect
github.com/shopspring/decimal v1.4.0 // indirect
go.opentelemetry.io/otel v1.35.0 // indirect
go.opentelemetry.io/otel/trace v1.35.0 // indirect
golang.org/x/sys v0.32.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
+112
View File
@@ -0,0 +1,112 @@
filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
github.com/ClickHouse/ch-go v0.65.1 h1:SLuxmLl5Mjj44/XbINsK2HFvzqup0s6rwKLFH347ZhU=
github.com/ClickHouse/ch-go v0.65.1/go.mod h1:bsodgURwmrkvkBe5jw1qnGDgyITsYErfONKAHn05nv4=
github.com/ClickHouse/clickhouse-go/v2 v2.34.0 h1:Y4rqkdrRHgExvC4o/NTbLdY5LFQ3LHS77/RNFxFX3Co=
github.com/ClickHouse/clickhouse-go/v2 v2.34.0/go.mod h1:yioSINoRLVZkLyDzdMXPLRIqhDvel8iLBlwh6Iefso8=
github.com/andybalholm/brotli v1.1.1 h1:PR2pgnyFznKEugtsUo0xLdDop5SKXd5Qf5ysW+7XdTA=
github.com/andybalholm/brotli v1.1.1/go.mod h1:05ib4cKhjx3OQYUY22hTVd34Bc8upXjOLL2rKwwZBoA=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/go-faster/city v1.0.1 h1:4WAxSZ3V2Ws4QRDrscLEDcibJY8uf41H6AhXDrNDcGw=
github.com/go-faster/city v1.0.1/go.mod h1:jKcUJId49qdW3L1qKHH/3wPeUstCVpVSXTM6vO3VcTw=
github.com/go-faster/errors v0.7.1 h1:MkJTnDoEdi9pDabt1dpWf7AA8/BaSYZqibYyhZ20AYg=
github.com/go-faster/errors v0.7.1/go.mod h1:5ySTjWFiphBs07IKuiL69nxdfd5+fzh1u7FPGZP2quo=
github.com/go-sql-driver/mysql v1.9.2 h1:4cNKDYQ1I84SXslGddlsrMhc8k4LeDVj6Ad6WRjiHuU=
github.com/go-sql-driver/mysql v1.9.2/go.mod h1:qn46aNg1333BRMNU69Lq93t8du/dwxI64Gl8i5p1WMU=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo=
github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ=
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc=
github.com/paulmach/orb v0.11.1 h1:3koVegMC4X/WeiXYz9iswopaTwMem53NzTJuTF20JzU=
github.com/paulmach/orb v0.11.1/go.mod h1:5mULz1xQfs3bmQm63QEJA6lNGujuRafwA5S/EnuLaLU=
github.com/paulmach/protoscan v0.2.1/go.mod h1:SpcSwydNLrxUGSDvXvO0P7g7AuhJ7lcKfDlhJCDw2gY=
github.com/pierrec/lz4/v4 v4.1.22 h1:cKFw6uJDK+/gfw5BcDL0JL5aBsAFdsIT18eRtLj7VIU=
github.com/pierrec/lz4/v4 v4.1.22/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/segmentio/asm v1.2.0 h1:9BQrFxC+YOHJlTlHGkTrFWf59nbL3XnCoFLTwDCI7ys=
github.com/segmentio/asm v1.2.0/go.mod h1:BqMnlJP91P8d+4ibuonYZw9mfnzI9HfxselHZr5aAcs=
github.com/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k=
github.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI=
github.com/xdg-go/scram v1.1.1/go.mod h1:RaEWvsqvNKKvBPvcKeFjrG2cJqOkHTiyTpzz23ni57g=
github.com/xdg-go/stringprep v1.0.3/go.mod h1:W3f5j4i+9rC0kuIEJL0ky1VpHXQU3ocBgklLGvcBnW8=
github.com/xyproto/randomstring v1.0.5 h1:YtlWPoRdgMu3NZtP45drfy1GKoojuR7hmRcnhZqKjWU=
github.com/xyproto/randomstring v1.0.5/go.mod h1:rgmS5DeNXLivK7YprL0pY+lTuhNQW3iGxZ18UQApw/E=
github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
go.mongodb.org/mongo-driver v1.11.4/go.mod h1:PTSz5yu21bkT/wXpkS7WR5f0ddqw5quethTUn9WM+2g=
go.opentelemetry.io/otel v1.35.0 h1:xKWKPxrxB6OtMCbmMY021CqC45J+3Onta9MqjhnusiQ=
go.opentelemetry.io/otel v1.35.0/go.mod h1:UEqy8Zp11hpkUrL73gSlELM0DupHoiq72dR+Zqel/+Y=
go.opentelemetry.io/otel/trace v1.35.0 h1:dPpEfJu1sDIqruz7BHFG3c7528f6ddfSWfFDVt/xgMs=
go.opentelemetry.io/otel/trace v1.35.0/go.mod h1:WUk7DtFp1Aw2MkvqGdwiXYDZZNvA/1J8o6xRXLrIkyc=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.32.0 h1:s77OFDvIQeibCmezSnk/q6iAfkdiQaJi4VzroCFrN20=
golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+69
View File
@@ -0,0 +1,69 @@
package main
import (
"context"
"database/sql"
"fmt"
"net"
"time"
"github.com/ClickHouse/clickhouse-go/v2"
_ "github.com/go-sql-driver/mysql"
)
func main() {
var dialCount int
conn, err := clickhouse.Open(&clickhouse.Options{
Addr: []string{"node-stable-1.db.cluster.zerops:9000"},
Auth: clickhouse.Auth{
Database: "cluster",
Username: "zerops",
Password: "uvKq9EnwUnXqKQEYcVTYzhoQ",
},
DialContext: func(ctx context.Context, addr string) (net.Conn, error) {
dialCount++
var d net.Dialer
return d.DialContext(ctx, "tcp", addr)
},
Debug: true,
Debugf: func(format string, v ...any) {
fmt.Printf(format+"\n", v...)
},
Settings: clickhouse.Settings{
"max_execution_time": 60,
},
Compression: &clickhouse.Compression{
Method: clickhouse.CompressionLZ4,
},
DialTimeout: time.Second * 30,
MaxOpenConns: 5,
MaxIdleConns: 5,
ConnMaxLifetime: time.Duration(10) * time.Minute,
ConnOpenStrategy: clickhouse.ConnOpenInOrder,
BlockBufferSize: 10,
MaxCompressionBuffer: 10240,
ClientInfo: clickhouse.ClientInfo{ // optional, please see Client info section in the README.md
Products: []struct {
Name string
Version string
}{
{Name: "my-app", Version: "0.1"},
},
},
})
if err != nil {
panic(err)
}
err = conn.Ping(context.Background())
if err != nil {
panic(err)
}
conn2, err := sql.Open("mysql", "zerops:uvKq9EnwUnXqKQEYcVTYzhoQ@tcp(node-stable-1.db.cluster.zerops:9004)/")
if err != nil {
panic(err)
}
err = conn2.Ping()
if err != nil {
panic(err)
}
}
+3
View File
@@ -0,0 +1,3 @@
module ddosbot
go 1.25.3
+95
View File
@@ -0,0 +1,95 @@
package main
import (
"fmt"
"log"
"net/http"
"os"
"strings"
"sync"
"sync/atomic"
"time"
)
func main() {
// Read URLs from environment variable
urlsEnv := os.Getenv("TARGET_URLS")
if urlsEnv == "" {
log.Fatal("TARGET_URLS environment variable is not set")
}
// Parse comma-delimited URLs
urls := strings.Split(urlsEnv, ",")
for i := range urls {
urls[i] = strings.TrimSpace(urls[i])
}
if len(urls) == 0 {
log.Fatal("No URLs provided")
}
fmt.Printf("Starting load test on %d URLs\n", len(urls))
fmt.Println("URLs:", urls)
fmt.Println("Press Ctrl+C to stop\n")
// Counters
var (
totalRequests uint64
successCount uint64
errorCount uint64
)
// WaitGroup to track all goroutines
var wg sync.WaitGroup
// Start time
startTime := time.Now()
// Spawn a goroutine for each URL
for _, url := range urls {
wg.Add(1)
go func(targetURL string) {
defer wg.Done()
client := &http.Client{Timeout: time.Second}
for {
resp, err := client.Get(targetURL)
atomic.AddUint64(&totalRequests, 1)
if err != nil {
fmt.Printf("error: %s => %v\n", targetURL, err)
atomic.AddUint64(&errorCount, 1)
continue
}
_ = resp.Body.Close()
if resp.StatusCode >= 200 && resp.StatusCode < 300 {
atomic.AddUint64(&successCount, 1)
} else {
fmt.Printf("bad status: %s => %d\n", targetURL, resp.StatusCode)
atomic.AddUint64(&errorCount, 1)
}
}
}(url)
}
// Progress reporter
go func() {
ticker := time.NewTicker(1 * time.Second)
defer ticker.Stop()
for {
<-ticker.C
elapsed := time.Since(startTime).Seconds()
requests := atomic.LoadUint64(&totalRequests)
success := atomic.LoadUint64(&successCount)
errors := atomic.LoadUint64(&errorCount)
fmt.Printf("Elapsed: %.0fs | Requests: %d | Success: %d | Errors: %d | Rate: %.0f req/s\n",
elapsed, requests, success, errors, float64(requests)/elapsed)
}
}()
// Wait for all goroutines (runs forever until killed)
wg.Wait()
}
+5
View File
@@ -0,0 +1,5 @@
services:
- hostname: ddosbot
zeropsSetup: ddosbot
type: go@1
minContainers: 10
+18
View File
@@ -0,0 +1,18 @@
zerops:
- setup: ddosbot
build:
os: alpine
base: go@latest
buildCommands:
- go build main.go
deployFiles:
- main
cache: true
run:
os: alpine
base: alpine@latest
envVariables:
TARGET_URLS: https://api-e5-8080.app-tor1.zerops.dev,https://api-e0-8080.app-tor1.zerops.dev,https://api-f2-8080.app-tor1.zerops.dev,https://api-f5-8080.app-tor1.zerops.dev,https://api-da-8080.app-tor1.zerops.dev,https://tor1.saidl.info,https://api-ee-8080.app-tor1.zerops.dev,https://api-ec-8080.app-tor1.zerops.dev,https://api-e1-8080.app-tor1.zerops.dev,https://api-e7-8080.app-tor1.zerops.dev,https://api-e4-8080.app-tor1.zerops.dev,https://api-e3-8080.app-tor1.zerops.dev,https://tor1a.saidl.info,https://api-d9-8080.app-tor1.zerops.dev,https://api-e2-8080.app-tor1.zerops.dev,https://api-e6-8080.app-tor1.zerops.dev,https://api-f0-8080.app-tor1.zerops.dev,https://api-d8-8080.app-tor1.zerops.dev,https://api-e9-8080.app-tor1.zerops.dev,https://api-e8-8080.app-tor1.zerops.dev
start: ./main
+13
View File
@@ -0,0 +1,13 @@
module elasticsearch
go 1.23.1
require (
github.com/elastic/elastic-transport-go/v8 v8.6.0 // indirect
github.com/elastic/go-elasticsearch/v8 v8.15.0 // indirect
github.com/go-logr/logr v1.4.2 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
go.opentelemetry.io/otel v1.31.0 // indirect
go.opentelemetry.io/otel/metric v1.31.0 // indirect
go.opentelemetry.io/otel/trace v1.31.0 // indirect
)
+15
View File
@@ -0,0 +1,15 @@
github.com/elastic/elastic-transport-go/v8 v8.6.0 h1:Y2S/FBjx1LlCv5m6pWAF2kDJAHoSjSRSJCApolgfthA=
github.com/elastic/elastic-transport-go/v8 v8.6.0/go.mod h1:YLHer5cj0csTzNFXoNQ8qhtGY1GTvSqPnKWKaqQE3Hk=
github.com/elastic/go-elasticsearch/v8 v8.15.0 h1:IZyJhe7t7WI3NEFdcHnf6IJXqpRf+8S8QWLtZYYyBYk=
github.com/elastic/go-elasticsearch/v8 v8.15.0/go.mod h1:HCON3zj4btpqs2N1jjsAy4a/fiAul+YBP00mBH4xik8=
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
go.opentelemetry.io/otel v1.31.0 h1:NsJcKPIW0D0H3NgzPDHmo0WW6SptzPdqg/L1zsIm2hY=
go.opentelemetry.io/otel v1.31.0/go.mod h1:O0C14Yl9FgkjqcCZAsE053C13OaddMYr/hz6clDkEJE=
go.opentelemetry.io/otel/metric v1.31.0 h1:FSErL0ATQAmYHUIzSezZibnyVlft1ybhy4ozRPcF2fE=
go.opentelemetry.io/otel/metric v1.31.0/go.mod h1:C3dEloVbLuYoX41KpmAhOqNriGbA+qqH6PQ5E5mUfnY=
go.opentelemetry.io/otel/trace v1.31.0 h1:ffjsj1aRouKewfr85U2aGagJ46+MvodynlQ1HYdmJys=
go.opentelemetry.io/otel/trace v1.31.0/go.mod h1:TXZkRk7SM2ZQLtR6eoAWQFIHPvzQ06FJAsO1tJg480A=
+116
View File
@@ -0,0 +1,116 @@
package main
import (
"context"
"encoding/json"
"flag"
"fmt"
"os/signal"
"syscall"
"time"
elasticsearch8 "github.com/elastic/go-elasticsearch/v8"
"github.com/elastic/go-elasticsearch/v8/typedapi/core/search"
"github.com/elastic/go-elasticsearch/v8/typedapi/types"
)
func main() {
var hostname string
var list, ha bool
flag.StringVar(&hostname, "host", "elastic.zerops", "hostname to connect to elastic")
flag.BoolVar(&list, "list", false, "whether to list the whole index")
flag.BoolVar(&ha, "ha", false, "is the cluster ha?")
flag.Parse()
ctx, stop := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM)
defer stop()
client, err := elasticsearch8.NewTypedClient(elasticsearch8.Config{
Addresses: []string{fmt.Sprintf("http://%s:9200", hostname)},
// Logger: &elastictransport.TextLogger{Output: os.Stdout, EnableRequestBody: true},
})
if err != nil {
panic(err)
}
const indexName = "my_index"
indicesExistsResponse, err := client.Indices.Exists(indexName).Do(ctx)
if err != nil {
panic(err)
}
if !indicesExistsResponse {
indicesCreateResponse, err := client.Indices.Create(indexName).Do(ctx)
if err != nil {
panic(err)
}
fmt.Println("created:", indicesCreateResponse.Index)
if !ha {
_, err = client.Indices.PutSettings().Indices(indexName).NumberOfReplicas("0").Do(ctx)
if err != nil {
panic(err)
}
}
} else {
fmt.Println("already exists:", indexName)
}
if list {
size := 10_000
searchResponse, err := client.Search().
Index(indexName).
Request(
&search.Request{
Query: &types.Query{
MatchAll: types.NewMatchAllQuery(),
},
Size: &size,
},
).
Do(ctx)
if err != nil {
panic(err)
}
for _, hit := range searchResponse.Hits.Hits {
var data map[string]any
_ = json.Unmarshal(hit.Source_, &data)
fmt.Printf("==> %s\n", data["message"])
}
}
for {
if ctx.Err() != nil {
fmt.Println("context canceled")
return
}
message := time.Now().Format(time.TimeOnly)
document := map[string]any{
"name": "yahoo",
"message": message,
}
indexResponse, err := client.Index(indexName).Request(document).Do(ctx)
if err != nil {
panic(err)
}
fmt.Printf("%s ==>\n", message)
getResponse, err := client.Get(indexName, indexResponse.Id_).Do(ctx)
if err != nil {
panic(err)
}
if !getResponse.Found {
fmt.Println("error: document not found")
continue
}
if getResponse.Id_ != indexResponse.Id_ {
fmt.Println("error: different ids")
continue
}
var data map[string]any
_ = json.Unmarshal(getResponse.Source_, &data)
fmt.Printf("==> %s\n", data["message"])
time.Sleep(time.Second)
}
}
+2
View File
@@ -0,0 +1,2 @@
node_modules
package-lock.json
+3
View File
@@ -0,0 +1,3 @@
module github.com/tikinang/godummy
go 1.23.1
View File
+14
View File
@@ -0,0 +1,14 @@
package main
import (
"fmt"
"net/http"
)
func main() {
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
_, _ = fmt.Fprintln(w, "OK")
})
_ = http.ListenAndServe(":8080", nil)
}
+9
View File
@@ -0,0 +1,9 @@
project:
name: test
services:
- hostname: app
type: alpine@latest
minContainers: 1
maxContainers: 1
buildFromGit: https://github.com/tikinang/godummy
enableSubdomainAccess: true
+6
View File
@@ -0,0 +1,6 @@
services:
- hostname: app2
type: alpine@latest
maxContainers: 1
buildFromGit: https://github.com/tikinang/godummy
enableSubdomainAccess: true
+17
View File
@@ -0,0 +1,17 @@
zerops:
- setup: app
build:
os: alpine
base: go@latest
buildCommands:
- go build -o app main.go
cache: true
deployFiles:
- app
run:
os: alpine
base: alpine@latest
ports:
- port: 8080
httpSupport: true
start: ./app
+2
View File
@@ -0,0 +1,2 @@
node_modules
package-lock.json
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+3
View File
@@ -0,0 +1,3 @@
module github.com/tikinang/test
go 1.24.0
+87
View File
@@ -0,0 +1,87 @@
package main
import (
"bytes"
"crypto/rand"
"flag"
"fmt"
"io"
mathrand "math/rand"
"os"
"sync"
"time"
)
var (
fsize int64
count int64
path string
chunk int64
)
func main() {
flag.Int64Var(&fsize, "fsizemb", 1, "file size mb")
flag.Int64Var(&chunk, "readsizekb", 4, "read chunk size kb")
flag.Int64Var(&count, "count", 16, "count")
flag.StringVar(&path, "path", "/var/www", "path")
flag.Parse()
fsize = fsize * 1024 * 1024
chunk = chunk * 1024
fmt.Printf("fsize: %d\n", fsize)
fmt.Printf("chunk: %d\n", chunk)
err := os.MkdirAll(path+"/files", 0755)
if err != nil {
panic(err)
}
wg := new(sync.WaitGroup)
for i := int64(0); i < count; i++ {
fname := fmt.Sprintf("%s/files/file_%d", path, i)
wg.Add(1)
go func(i int64) {
defer wg.Done()
manipulateFile(i, fname)
}(i)
}
wg.Wait()
}
func manipulateFile(i int64, fname string) {
file, err := os.Create(fname)
if err != nil {
panic(err)
}
defer file.Close()
in := io.LimitReader(rand.Reader, fsize)
wrote, err := io.Copy(file, in)
if err != nil {
panic(err)
}
fmt.Printf("[%d]: wrote: %s: %d\n", i, fname, wrote)
for {
time.Sleep(time.Duration(mathrand.Intn(500)+200) * time.Millisecond)
offset := mathrand.Int63n(fsize)
size := chunk
if offset+size > fsize {
size = fsize - offset
}
seeked, err := file.Seek(offset, io.SeekStart)
if err != nil {
fmt.Printf("[%d]: seek error: %s\n", i, err)
continue
}
fmt.Printf("[%d]: seek offset: %d\n", i, seeked)
b := bytes.NewBuffer(make([]byte, 0, size))
read, err := io.Copy(b, io.LimitReader(file, size))
if err != nil {
fmt.Printf("[%d]: read error: %s\n", i, err)
continue
}
fmt.Printf("[%d]: read: %d\n", i, read)
}
}
+14
View File
@@ -0,0 +1,14 @@
zerops:
- setup: app
build:
os: alpine
base:
- go@1
buildCommands:
- go build -o cacher main.go
cache: true
deployFiles:
- cacher
run:
os: ubuntu
base: ubuntu@latest
+5
View File
@@ -0,0 +1,5 @@
module hedgedocindex
go 1.24.0
require github.com/lib/pq v1.10.9 // indirect
+2
View File
@@ -0,0 +1,2 @@
github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
+63
View File
@@ -0,0 +1,63 @@
package main
import (
"database/sql"
"fmt"
"net/http"
"os"
"strings"
_ "github.com/lib/pq"
)
func main() {
db, err := sql.Open("postgres", os.Getenv("DATABASE_CONNECTION_STRING"))
if err != nil {
panic(err)
}
err = db.Ping()
if err != nil {
panic(err)
}
http.HandleFunc("/favicon.ico", func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusNotFound) })
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
rows, err := db.Query(`SELECT id, alias, title FROM "Notes" WHERE alias IS NOT NULL AND "permission" IN ('freely', 'editable', 'limited') ORDER BY "createdAt" DESC`)
if err != nil {
w.WriteHeader(http.StatusServiceUnavailable)
fmt.Fprintln(os.Stderr, err)
return
}
defer rows.Close()
w.Header().Add("Content-Type", "text/html")
w.WriteHeader(http.StatusOK)
_, _ = fmt.Fprintln(w, "<html>")
_, _ = fmt.Fprintln(w, "<ul>")
for rows.Next() {
var id, title, alias string
err = rows.Scan(&id, &alias, &title)
if err != nil {
w.WriteHeader(http.StatusServiceUnavailable)
fmt.Fprintln(os.Stderr, err)
return
}
// fmt.Println(id, alias)
url := strings.TrimSuffix(os.Getenv("HEDGEDOC_URL"), "/") + "/" + alias
_, _ = fmt.Fprintln(w, "<li>")
_, _ = fmt.Fprintf(w, `%s (<a href="%s">%s</a>)`, title, url, url)
_, _ = fmt.Fprintln(w, "</li>")
}
_, _ = fmt.Fprintln(w, "</ul>")
_, _ = fmt.Fprintln(w, "</html>")
})
fmt.Fprintln(os.Stderr, "listening on :8080")
err = http.ListenAndServe(":8080", http.DefaultServeMux)
if err != nil {
panic(err)
}
}
+21
View File
@@ -0,0 +1,21 @@
zerops:
- setup: hedgedocindex
build:
os: alpine
base:
- go@latest
buildCommands:
- go build -o app main.go
cache: true
deployFiles:
- app
run:
os: alpine
base: alpine@latest
envVariables:
HEDGEDOC_URL: https://hedgedoc.zerops.io
DATABASE_CONNECTION_STRING: ${docdb_connectionString}/${docdb_dbName}
ports:
- port: 8080
httpSupport: true
start: ./app
+15
View File
@@ -0,0 +1,15 @@
module kafka
go 1.23.1
require (
github.com/twmb/franz-go v1.17.1
github.com/twmb/franz-go/pkg/kadm v1.13.0
)
require (
github.com/klauspost/compress v1.17.8 // indirect
github.com/pierrec/lz4/v4 v4.1.21 // indirect
github.com/twmb/franz-go/pkg/kmsg v1.8.0 // indirect
golang.org/x/crypto v0.23.0 // indirect
)
+12
View File
@@ -0,0 +1,12 @@
github.com/klauspost/compress v1.17.8 h1:YcnTYrq7MikUT7k0Yb5eceMmALQPYBW/Xltxn0NAMnU=
github.com/klauspost/compress v1.17.8/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
github.com/pierrec/lz4/v4 v4.1.21 h1:yOVMLb6qSIDP67pl/5F7RepeKYu/VmTyEXvuMI5d9mQ=
github.com/pierrec/lz4/v4 v4.1.21/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
github.com/twmb/franz-go v1.17.1 h1:0LwPsbbJeJ9R91DPUHSEd4su82WJWcTY1Zzbgbg4CeQ=
github.com/twmb/franz-go v1.17.1/go.mod h1:NreRdJ2F7dziDY/m6VyspWd6sNxHKXdMZI42UfQ3GXM=
github.com/twmb/franz-go/pkg/kadm v1.13.0 h1:bJq4C2ZikUE2jh/wl9MtMTQ/kpmnBgVFh8XMQBEC+60=
github.com/twmb/franz-go/pkg/kadm v1.13.0/go.mod h1:VMvpfjz/szpH9WB+vGM+rteTzVv0djyHFimci9qm2C0=
github.com/twmb/franz-go/pkg/kmsg v1.8.0 h1:lAQB9Z3aMrIP9qF9288XcFf/ccaSxEitNA1CDTEIeTA=
github.com/twmb/franz-go/pkg/kmsg v1.8.0/go.mod h1:HzYEb8G3uu5XevZbtU0dVbkphaKTHk0X68N5ka4q6mU=
golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI=
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
+92
View File
@@ -0,0 +1,92 @@
package main
import (
"context"
"flag"
"fmt"
"time"
"github.com/twmb/franz-go/pkg/kadm"
"github.com/twmb/franz-go/pkg/kgo"
"github.com/twmb/franz-go/pkg/sasl/plain"
)
func main() {
ctx := context.Background()
var password, hostname string
var replication int
flag.StringVar(&password, "p", "", "password to connect to kafka")
flag.StringVar(&hostname, "h", "kafka", "hostname to connect to kafka")
flag.IntVar(&replication, "r", 3, "number of replication")
flag.Parse()
seeds := []string{fmt.Sprintf("%s.zerops:9092", hostname)}
cl, err := kgo.NewClient(
kgo.SeedBrokers(seeds...),
kgo.SASL(plain.Auth{
User: "zerops",
Pass: password,
}.AsMechanism()),
)
if err != nil {
panic(err)
}
defer cl.Close()
adminClient := kadm.NewClient(cl)
topic, err := adminClient.ListTopics(ctx, "foo")
if err != nil {
panic(err)
}
// if topic.Error() != nil {
// panic(topic.Error())
// }
if !topic.Has("foo") {
partitions := int32(6)
if replication == 1 {
partitions = 1
}
resp, err := adminClient.CreateTopic(ctx, partitions, int16(replication), nil, "foo")
if err != nil {
panic(err)
}
if resp.Err != nil {
panic(resp.Err)
}
}
go func() {
for {
message := time.Now().Format(time.TimeOnly)
fmt.Printf("%s ==>\n", message)
// Alternatively, ProduceSync exists to synchronously produce a batch of records.
record := &kgo.Record{Topic: "foo", Value: []byte(message)}
if err := cl.ProduceSync(ctx, record).FirstErr(); err != nil {
fmt.Printf("record had a produce error while synchronously producing: %v\n", err)
}
time.Sleep(time.Second)
}
}()
cl.AddConsumeTopics("foo")
for {
fetches := cl.PollFetches(ctx)
if fetches.IsClientClosed() {
fmt.Println("closed ")
return
}
if errs := fetches.Errors(); len(errs) > 0 {
// All errors are retried internally when fetching, but non-retriable errors are
// returned from polls so that users can notice and take action.
panic(fmt.Sprint(errs))
}
// We can iterate through a record iterator...
iter := fetches.RecordIter()
for !iter.Done() {
record := iter.Next()
fmt.Printf("==> %s\n", string(record.Value))
}
}
}
+10
View File
@@ -0,0 +1,10 @@
module meilisearch
go 1.23.1
require (
github.com/golang-jwt/jwt/v4 v4.5.0 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/mailru/easyjson v0.7.7 // indirect
github.com/meilisearch/meilisearch-go v0.28.0 // indirect
)
+20
View File
@@ -0,0 +1,20 @@
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg=
github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
github.com/meilisearch/meilisearch-go v0.28.0 h1:f3XJ66ZM+R8bANAOLqsjvoq/HhQNpVJPYoNt6QgNzME=
github.com/meilisearch/meilisearch-go v0.28.0/go.mod h1:Szcc9CaDiKIfjdgdt49jlmDKpEzjD+x+b6Y6heMdlQ0=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+107
View File
@@ -0,0 +1,107 @@
package main
import (
"context"
"flag"
"fmt"
"os/signal"
"syscall"
"time"
"github.com/meilisearch/meilisearch-go"
)
func main() {
var hostname, masterKey string
var list bool
flag.StringVar(&hostname, "host", "meili.zerops", "hostname to connect to elastic")
flag.StringVar(&masterKey, "key", "nope", "master key")
flag.BoolVar(&list, "list", false, "whether to list the whole index")
flag.Parse()
ctx, stop := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM)
defer stop()
client := meilisearch.New(fmt.Sprintf("http://%s:7700", hostname), meilisearch.WithAPIKey(masterKey))
const indexName = "xxx"
taskInfo, err := client.CreateIndexWithContext(ctx, &meilisearch.IndexConfig{
Uid: indexName,
PrimaryKey: "id",
})
if err != nil {
panic(err)
}
status := taskInfo.Status
var taskErr any
for status != "succeeded" {
if status == "failed" || status == "canceled" {
fmt.Println("task failed:", taskErr)
break
}
task, err := client.GetTaskWithContext(ctx, taskInfo.TaskUID)
if err != nil {
panic(err)
}
status = task.Status
taskErr = task.Error
}
indices, err := client.ListIndexesWithContext(ctx, &meilisearch.IndexesQuery{})
if err != nil {
panic(err)
}
for _, index := range indices.Results {
fmt.Println(index.UID, index.PrimaryKey)
}
index := client.Index(indexName)
if list {
resp, err := index.SearchWithContext(ctx, "*", &meilisearch.SearchRequest{Limit: 1024 * 1024})
if err != nil {
panic(err)
}
for _, hit := range resp.Hits {
fmt.Printf("LIST: ==> %s\n", hit.(map[string]any)["message"])
}
}
for {
if ctx.Err() != nil {
fmt.Println("context canceled")
return
}
now := time.Now()
message := now.Format(time.TimeOnly)
document := map[string]any{
"id": now.UnixNano(),
"name": "meili",
"message": message,
}
taskInfo, err = index.AddDocumentsWithContext(ctx, []map[string]any{document})
if err != nil {
panic(err)
}
status = taskInfo.Status
for status != "succeeded" {
if status == "failed" || status == "canceled" {
fmt.Println("task failed:", taskErr)
break
}
task, err := index.GetTaskWithContext(ctx, taskInfo.TaskUID)
if err != nil {
panic(err)
}
status = task.Status
taskErr = task.Error
}
fmt.Printf("==> %s\n", document["message"])
time.Sleep(time.Second)
}
}
+14
View File
@@ -0,0 +1,14 @@
module nats
go 1.23.1
require github.com/nats-io/nats.go v1.37.0
require (
github.com/klauspost/compress v1.17.2 // indirect
github.com/nats-io/nkeys v0.4.7 // indirect
github.com/nats-io/nuid v1.0.1 // indirect
golang.org/x/crypto v0.18.0 // indirect
golang.org/x/sys v0.16.0 // indirect
golang.org/x/text v0.14.0 // indirect
)
+14
View File
@@ -0,0 +1,14 @@
github.com/klauspost/compress v1.17.2 h1:RlWWUY/Dr4fL8qk9YG7DTZ7PDgME2V4csBXA8L/ixi4=
github.com/klauspost/compress v1.17.2/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
github.com/nats-io/nats.go v1.37.0 h1:07rauXbVnnJvv1gfIyghFEo6lUcYRY0WXc3x7x0vUxE=
github.com/nats-io/nats.go v1.37.0/go.mod h1:Ubdu4Nh9exXdSz0RVWRFBbRfrbSxOYd26oF0wkWclB8=
github.com/nats-io/nkeys v0.4.7 h1:RwNJbbIdYCoClSDNY7QVKZlyb/wfT6ugvFCiKy6vDvI=
github.com/nats-io/nkeys v0.4.7/go.mod h1:kqXRgRDPlGy7nGaEDMuYzmiJCIAAWDK0IMBtDmGD0nc=
github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw=
github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c=
golang.org/x/crypto v0.18.0 h1:PGVlW0xEltQnzFZ55hkuX5+KLyrMYhHld1YHO4AKcdc=
golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg=
golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU=
golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
+70
View File
@@ -0,0 +1,70 @@
package main
import (
"context"
"flag"
"fmt"
"os"
"os/signal"
"time"
"github.com/nats-io/nats.go"
"github.com/nats-io/nats.go/jetstream"
)
func main() {
var testJetStream bool
var password, host string
flag.StringVar(&password, "p", "", "password")
flag.StringVar(&host, "h", "nats", "hostname")
flag.BoolVar(&testJetStream, "js", false, "jetstream")
flag.Parse()
ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt)
defer stop()
nc, err := nats.Connect(fmt.Sprintf("nats://zerops:%s@%s:4222", password, host))
if err != nil {
panic(err)
}
defer nc.Close()
js, err := jetstream.New(nc)
if err != nil {
panic(err)
}
stream, err := js.CreateOrUpdateStream(ctx, jetstream.StreamConfig{Name: "stream1"})
if err != nil {
panic(err)
}
consumer, err := stream.CreateOrUpdateConsumer(ctx, jetstream.ConsumerConfig{Name: "consumer1"})
if err != nil {
panic(err)
}
_, err = consumer.Consume(func(msg jetstream.Msg) {
fmt.Printf("==> %s\n", string(msg.Data()))
_ = msg.Ack()
})
if err != nil {
panic(err)
}
for {
if ctx.Err() != nil {
break
}
message := time.Now().Format(time.TimeOnly)
fmt.Printf("%s ==>\n", message)
_, err = js.Publish(ctx, "stream1", []byte(message))
if err != nil {
fmt.Println(err)
break
}
time.Sleep(time.Second)
}
<-ctx.Done()
}
+51
View File
@@ -0,0 +1,51 @@
# See https://docs.docker.com/engine/reference/builder/#dockerignore-file for more about ignoring files.
# Ignore git directory.
/.git/
/.gitignore
# Ignore bundler config.
/.bundle
# Ignore all environment files.
/.env*
# Ignore all default key files.
/config/master.key
/config/credentials/*.key
# Ignore all logfiles and tempfiles.
/log/*
/tmp/*
!/log/.keep
!/tmp/.keep
# Ignore pidfiles, but keep the directory.
/tmp/pids/*
!/tmp/pids/.keep
# Ignore storage (uploaded files in development and any SQLite databases).
/storage/*
!/storage/.keep
/tmp/storage/*
!/tmp/storage/.keep
# Ignore assets.
/node_modules/
/app/assets/builds/*
!/app/assets/builds/.keep
/public/assets
# Ignore CI service files.
/.github
# Ignore Kamal files.
/config/deploy*.yml
/.kamal
# Ignore development files
/.devcontainer
# Ignore Docker-related files
/.dockerignore
/Dockerfile*
+9
View File
@@ -0,0 +1,9 @@
# See https://git-scm.com/docs/gitattributes for more about git attribute files.
# Mark the database schema as having been generated.
db/schema.rb linguist-generated
# Mark any vendored files as having been vendored.
vendor/* linguist-vendored
config/credentials/*.yml.enc diff=rails_credentials
config/credentials.yml.enc diff=rails_credentials
+12
View File
@@ -0,0 +1,12 @@
version: 2
updates:
- package-ecosystem: bundler
directory: "/"
schedule:
interval: daily
open-pull-requests-limit: 10
- package-ecosystem: github-actions
directory: "/"
schedule:
interval: daily
open-pull-requests-limit: 10
+90
View File
@@ -0,0 +1,90 @@
name: CI
on:
pull_request:
push:
branches: [ main ]
jobs:
scan_ruby:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Ruby
uses: ruby/setup-ruby@v1
with:
ruby-version: .ruby-version
bundler-cache: true
- name: Scan for common Rails security vulnerabilities using static analysis
run: bin/brakeman --no-pager
scan_js:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Ruby
uses: ruby/setup-ruby@v1
with:
ruby-version: .ruby-version
bundler-cache: true
- name: Scan for security vulnerabilities in JavaScript dependencies
run: bin/importmap audit
lint:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Ruby
uses: ruby/setup-ruby@v1
with:
ruby-version: .ruby-version
bundler-cache: true
- name: Lint code for consistent style
run: bin/rubocop -f github
test:
runs-on: ubuntu-latest
# services:
# redis:
# image: redis
# ports:
# - 6379:6379
# options: --health-cmd "redis-cli ping" --health-interval 10s --health-timeout 5s --health-retries 5
steps:
- name: Install packages
run: sudo apt-get update && sudo apt-get install --no-install-recommends -y build-essential git libyaml-dev pkg-config google-chrome-stable
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Ruby
uses: ruby/setup-ruby@v1
with:
ruby-version: .ruby-version
bundler-cache: true
- name: Run tests
env:
RAILS_ENV: test
# REDIS_URL: redis://localhost:6379/0
run: bin/rails db:test:prepare test test:system
- name: Keep screenshots from failed system tests
uses: actions/upload-artifact@v4
if: failure()
with:
name: screenshots
path: ${{ github.workspace }}/tmp/screenshots
if-no-files-found: ignore
+34
View File
@@ -0,0 +1,34 @@
# See https://help.github.com/articles/ignoring-files for more about ignoring files.
#
# Temporary files generated by your text editor or operating system
# belong in git's global ignore instead:
# `$XDG_CONFIG_HOME/git/ignore` or `~/.config/git/ignore`
# Ignore bundler config.
/.bundle
# Ignore all environment files.
/.env*
# Ignore all logfiles and tempfiles.
/log/*
/tmp/*
!/log/.keep
!/tmp/.keep
# Ignore pidfiles, but keep the directory.
/tmp/pids/*
!/tmp/pids/
!/tmp/pids/.keep
# Ignore storage (uploaded files in development and any SQLite databases).
/storage/*
!/storage/.keep
/tmp/storage/*
!/tmp/storage/
!/tmp/storage/.keep
/public/assets
# Ignore master key for decrypting credentials and more.
/config/master.key
+3
View File
@@ -0,0 +1,3 @@
#!/bin/sh
echo "Docker set up on $KAMAL_HOSTS..."
+3
View File
@@ -0,0 +1,3 @@
#!/bin/sh
echo "Booted app version $KAMAL_VERSION on $KAMAL_HOSTS..."
+14
View File
@@ -0,0 +1,14 @@
#!/bin/sh
# A sample post-deploy hook
#
# These environment variables are available:
# KAMAL_RECORDED_AT
# KAMAL_PERFORMER
# KAMAL_VERSION
# KAMAL_HOSTS
# KAMAL_ROLE (if set)
# KAMAL_DESTINATION (if set)
# KAMAL_RUNTIME
echo "$KAMAL_PERFORMER deployed $KAMAL_VERSION to $KAMAL_DESTINATION in $KAMAL_RUNTIME seconds"
+3
View File
@@ -0,0 +1,3 @@
#!/bin/sh
echo "Rebooted kamal-proxy on $KAMAL_HOSTS"
+3
View File
@@ -0,0 +1,3 @@
#!/bin/sh
echo "Booting app version $KAMAL_VERSION on $KAMAL_HOSTS..."
+51
View File
@@ -0,0 +1,51 @@
#!/bin/sh
# A sample pre-build hook
#
# Checks:
# 1. We have a clean checkout
# 2. A remote is configured
# 3. The branch has been pushed to the remote
# 4. The version we are deploying matches the remote
#
# These environment variables are available:
# KAMAL_RECORDED_AT
# KAMAL_PERFORMER
# KAMAL_VERSION
# KAMAL_HOSTS
# KAMAL_ROLE (if set)
# KAMAL_DESTINATION (if set)
if [ -n "$(git status --porcelain)" ]; then
echo "Git checkout is not clean, aborting..." >&2
git status --porcelain >&2
exit 1
fi
first_remote=$(git remote)
if [ -z "$first_remote" ]; then
echo "No git remote set, aborting..." >&2
exit 1
fi
current_branch=$(git branch --show-current)
if [ -z "$current_branch" ]; then
echo "Not on a git branch, aborting..." >&2
exit 1
fi
remote_head=$(git ls-remote $first_remote --tags $current_branch | cut -f1)
if [ -z "$remote_head" ]; then
echo "Branch not pushed to remote, aborting..." >&2
exit 1
fi
if [ "$KAMAL_VERSION" != "$remote_head" ]; then
echo "Version ($KAMAL_VERSION) does not match remote HEAD ($remote_head), aborting..." >&2
exit 1
fi
exit 0
+47
View File
@@ -0,0 +1,47 @@
#!/usr/bin/env ruby
# A sample pre-connect check
#
# Warms DNS before connecting to hosts in parallel
#
# These environment variables are available:
# KAMAL_RECORDED_AT
# KAMAL_PERFORMER
# KAMAL_VERSION
# KAMAL_HOSTS
# KAMAL_ROLE (if set)
# KAMAL_DESTINATION (if set)
# KAMAL_RUNTIME
hosts = ENV["KAMAL_HOSTS"].split(",")
results = nil
max = 3
elapsed = Benchmark.realtime do
results = hosts.map do |host|
Thread.new do
tries = 1
begin
Socket.getaddrinfo(host, 0, Socket::AF_UNSPEC, Socket::SOCK_STREAM, nil, Socket::AI_CANONNAME)
rescue SocketError
if tries < max
puts "Retrying DNS warmup: #{host}"
tries += 1
sleep rand
retry
else
puts "DNS warmup failed: #{host}"
host
end
end
tries
end
end.map(&:value)
end
retries = results.sum - hosts.size
nopes = results.count { |r| r == max }
puts "Prewarmed %d DNS lookups in %.2f sec: %d retries, %d failures" % [ hosts.size, elapsed, retries, nopes ]
+109
View File
@@ -0,0 +1,109 @@
#!/usr/bin/env ruby
# A sample pre-deploy hook
#
# Checks the Github status of the build, waiting for a pending build to complete for up to 720 seconds.
#
# Fails unless the combined status is "success"
#
# These environment variables are available:
# KAMAL_RECORDED_AT
# KAMAL_PERFORMER
# KAMAL_VERSION
# KAMAL_HOSTS
# KAMAL_COMMAND
# KAMAL_SUBCOMMAND
# KAMAL_ROLE (if set)
# KAMAL_DESTINATION (if set)
# Only check the build status for production deployments
if ENV["KAMAL_COMMAND"] == "rollback" || ENV["KAMAL_DESTINATION"] != "production"
exit 0
end
require "bundler/inline"
# true = install gems so this is fast on repeat invocations
gemfile(true, quiet: true) do
source "https://rubygems.org"
gem "octokit"
gem "faraday-retry"
end
MAX_ATTEMPTS = 72
ATTEMPTS_GAP = 10
def exit_with_error(message)
$stderr.puts message
exit 1
end
class GithubStatusChecks
attr_reader :remote_url, :git_sha, :github_client, :combined_status
def initialize
@remote_url = `git config --get remote.origin.url`.strip.delete_prefix("https://github.com/")
@git_sha = `git rev-parse HEAD`.strip
@github_client = Octokit::Client.new(access_token: ENV["GITHUB_TOKEN"])
refresh!
end
def refresh!
@combined_status = github_client.combined_status(remote_url, git_sha)
end
def state
combined_status[:state]
end
def first_status_url
first_status = combined_status[:statuses].find { |status| status[:state] == state }
first_status && first_status[:target_url]
end
def complete_count
combined_status[:statuses].count { |status| status[:state] != "pending"}
end
def total_count
combined_status[:statuses].count
end
def current_status
if total_count > 0
"Completed #{complete_count}/#{total_count} checks, see #{first_status_url} ..."
else
"Build not started..."
end
end
end
$stdout.sync = true
puts "Checking build status..."
attempts = 0
checks = GithubStatusChecks.new
begin
loop do
case checks.state
when "success"
puts "Checks passed, see #{checks.first_status_url}"
exit 0
when "failure"
exit_with_error "Checks failed, see #{checks.first_status_url}"
when "pending"
attempts += 1
end
exit_with_error "Checks are still pending, gave up after #{MAX_ATTEMPTS * ATTEMPTS_GAP} seconds" if attempts == MAX_ATTEMPTS
puts checks.current_status
sleep(ATTEMPTS_GAP)
checks.refresh!
end
rescue Octokit::NotFound
exit_with_error "Build status could not be found"
end
+3
View File
@@ -0,0 +1,3 @@
#!/bin/sh
echo "Rebooting kamal-proxy on $KAMAL_HOSTS..."
+17
View File
@@ -0,0 +1,17 @@
# Secrets defined here are available for reference under registry/password, env/secret, builder/secrets,
# and accessories/*/env/secret in config/deploy.yml. All secrets should be pulled from either
# password manager, ENV, or a file. DO NOT ENTER RAW CREDENTIALS HERE! This file needs to be safe for git.
# Example of extracting secrets from 1password (or another compatible pw manager)
# SECRETS=$(kamal secrets fetch --adapter 1password --account your-account --from Vault/Item KAMAL_REGISTRY_PASSWORD RAILS_MASTER_KEY)
# KAMAL_REGISTRY_PASSWORD=$(kamal secrets extract KAMAL_REGISTRY_PASSWORD ${SECRETS})
# RAILS_MASTER_KEY=$(kamal secrets extract RAILS_MASTER_KEY ${SECRETS})
# Use a GITHUB_TOKEN if private repositories are needed for the image
# GITHUB_TOKEN=$(gh config get -h github.com oauth_token)
# Grab the registry password from ENV
KAMAL_REGISTRY_PASSWORD=$KAMAL_REGISTRY_PASSWORD
# Improve security by using a password manager. Never check config/master.key into git!
RAILS_MASTER_KEY=$(cat config/master.key)
+8
View File
@@ -0,0 +1,8 @@
# Omakase Ruby styling for Rails
inherit_gem: { rubocop-rails-omakase: rubocop.yml }
# Overwrite or add rules to create your own house style
#
# # Use `[a, [b, c]]` not `[ a, [ b, c ] ]`
# Layout/SpaceInsideArrayLiteralBrackets:
# Enabled: false
+1
View File
@@ -0,0 +1 @@
ruby-3.4.2
+72
View File
@@ -0,0 +1,72 @@
# syntax=docker/dockerfile:1
# check=error=true
# This Dockerfile is designed for production, not development. Use with Kamal or build'n'run by hand:
# docker build -t ruby .
# docker run -d -p 80:80 -e RAILS_MASTER_KEY=<value from config/master.key> --name ruby ruby
# For a containerized dev environment, see Dev Containers: https://guides.rubyonrails.org/getting_started_with_devcontainer.html
# Make sure RUBY_VERSION matches the Ruby version in .ruby-version
ARG RUBY_VERSION=3.4.2
FROM docker.io/library/ruby:$RUBY_VERSION-slim AS base
# Rails app lives here
WORKDIR /rails
# Install base packages
RUN apt-get update -qq && \
apt-get install --no-install-recommends -y curl libjemalloc2 libvips sqlite3 && \
rm -rf /var/lib/apt/lists /var/cache/apt/archives
# Set production environment
ENV RAILS_ENV="production" \
BUNDLE_DEPLOYMENT="1" \
BUNDLE_PATH="/usr/local/bundle" \
BUNDLE_WITHOUT="development"
# Throw-away build stage to reduce size of final image
FROM base AS build
# Install packages needed to build gems
RUN apt-get update -qq && \
apt-get install --no-install-recommends -y build-essential git libyaml-dev pkg-config && \
rm -rf /var/lib/apt/lists /var/cache/apt/archives
# Install application gems
COPY Gemfile Gemfile.lock ./
RUN bundle install && \
rm -rf ~/.bundle/ "${BUNDLE_PATH}"/ruby/*/cache "${BUNDLE_PATH}"/ruby/*/bundler/gems/*/.git && \
bundle exec bootsnap precompile --gemfile
# Copy application code
COPY . .
# Precompile bootsnap code for faster boot times
RUN bundle exec bootsnap precompile app/ lib/
# Precompiling assets for production without requiring secret RAILS_MASTER_KEY
RUN SECRET_KEY_BASE_DUMMY=1 ./bin/rails assets:precompile
# Final stage for app image
FROM base
# Copy built artifacts: gems, application
COPY --from=build "${BUNDLE_PATH}" "${BUNDLE_PATH}"
COPY --from=build /rails /rails
# Run and own only the runtime files as a non-root user for security
RUN groupadd --system --gid 1000 rails && \
useradd rails --uid 1000 --gid 1000 --create-home --shell /bin/bash && \
chown -R rails:rails db log storage tmp
USER 1000:1000
# Entrypoint prepares the database.
ENTRYPOINT ["/rails/bin/docker-entrypoint"]
# Start server via Thruster by default, this can be overwritten at runtime
EXPOSE 80
CMD ["./bin/thrust", "./bin/rails", "server"]
+63
View File
@@ -0,0 +1,63 @@
source "https://rubygems.org"
# Bundle edge Rails instead: gem "rails", github: "rails/rails", branch: "main"
gem "rails", "~> 8.0.2"
# The modern asset pipeline for Rails [https://github.com/rails/propshaft]
gem "propshaft"
# Use sqlite3 as the database for Active Record
gem "sqlite3", ">= 2.1"
# Use the Puma web server [https://github.com/puma/puma]
gem "puma", ">= 5.0"
# Use JavaScript with ESM import maps [https://github.com/rails/importmap-rails]
gem "importmap-rails"
# Hotwire's SPA-like page accelerator [https://turbo.hotwired.dev]
gem "turbo-rails"
# Hotwire's modest JavaScript framework [https://stimulus.hotwired.dev]
gem "stimulus-rails"
# Build JSON APIs with ease [https://github.com/rails/jbuilder]
gem "jbuilder"
# Use Active Model has_secure_password [https://guides.rubyonrails.org/active_model_basics.html#securepassword]
# gem "bcrypt", "~> 3.1.7"
# Windows does not include zoneinfo files, so bundle the tzinfo-data gem
gem "tzinfo-data", platforms: %i[ windows jruby ]
# Use the database-backed adapters for Rails.cache, Active Job, and Action Cable
gem "solid_cache"
gem "solid_queue"
gem "solid_cable"
# Reduces boot times through caching; required in config/boot.rb
gem "bootsnap", require: false
# Deploy this application anywhere as a Docker container [https://kamal-deploy.org]
gem "kamal", require: false
# Add HTTP asset caching/compression and X-Sendfile acceleration to Puma [https://github.com/basecamp/thruster/]
gem "thruster", require: false
# Use Active Storage variants [https://guides.rubyonrails.org/active_storage_overview.html#transforming-images]
# gem "image_processing", "~> 1.2"
group :development, :test do
# See https://guides.rubyonrails.org/debugging_rails_applications.html#debugging-with-the-debug-gem
gem "debug", platforms: %i[ mri windows ], require: "debug/prelude"
# Static analysis for security vulnerabilities [https://brakemanscanner.org/]
gem "brakeman", require: false
# Omakase Ruby styling [https://github.com/rails/rubocop-rails-omakase/]
gem "rubocop-rails-omakase", require: false
end
group :development do
# Use console on exceptions pages [https://github.com/rails/web-console]
gem "web-console"
end
group :test do
# Use system testing [https://guides.rubyonrails.org/testing.html#system-testing]
gem "capybara"
gem "selenium-webdriver"
end
+383
View File
@@ -0,0 +1,383 @@
GEM
remote: https://rubygems.org/
specs:
actioncable (8.0.2)
actionpack (= 8.0.2)
activesupport (= 8.0.2)
nio4r (~> 2.0)
websocket-driver (>= 0.6.1)
zeitwerk (~> 2.6)
actionmailbox (8.0.2)
actionpack (= 8.0.2)
activejob (= 8.0.2)
activerecord (= 8.0.2)
activestorage (= 8.0.2)
activesupport (= 8.0.2)
mail (>= 2.8.0)
actionmailer (8.0.2)
actionpack (= 8.0.2)
actionview (= 8.0.2)
activejob (= 8.0.2)
activesupport (= 8.0.2)
mail (>= 2.8.0)
rails-dom-testing (~> 2.2)
actionpack (8.0.2)
actionview (= 8.0.2)
activesupport (= 8.0.2)
nokogiri (>= 1.8.5)
rack (>= 2.2.4)
rack-session (>= 1.0.1)
rack-test (>= 0.6.3)
rails-dom-testing (~> 2.2)
rails-html-sanitizer (~> 1.6)
useragent (~> 0.16)
actiontext (8.0.2)
actionpack (= 8.0.2)
activerecord (= 8.0.2)
activestorage (= 8.0.2)
activesupport (= 8.0.2)
globalid (>= 0.6.0)
nokogiri (>= 1.8.5)
actionview (8.0.2)
activesupport (= 8.0.2)
builder (~> 3.1)
erubi (~> 1.11)
rails-dom-testing (~> 2.2)
rails-html-sanitizer (~> 1.6)
activejob (8.0.2)
activesupport (= 8.0.2)
globalid (>= 0.3.6)
activemodel (8.0.2)
activesupport (= 8.0.2)
activerecord (8.0.2)
activemodel (= 8.0.2)
activesupport (= 8.0.2)
timeout (>= 0.4.0)
activestorage (8.0.2)
actionpack (= 8.0.2)
activejob (= 8.0.2)
activerecord (= 8.0.2)
activesupport (= 8.0.2)
marcel (~> 1.0)
activesupport (8.0.2)
base64
benchmark (>= 0.3)
bigdecimal
concurrent-ruby (~> 1.0, >= 1.3.1)
connection_pool (>= 2.2.5)
drb
i18n (>= 1.6, < 2)
logger (>= 1.4.2)
minitest (>= 5.1)
securerandom (>= 0.3)
tzinfo (~> 2.0, >= 2.0.5)
uri (>= 0.13.1)
addressable (2.8.7)
public_suffix (>= 2.0.2, < 7.0)
ast (2.4.3)
base64 (0.2.0)
bcrypt_pbkdf (1.1.1)
benchmark (0.4.0)
bigdecimal (3.1.9)
bindex (0.8.1)
bootsnap (1.18.4)
msgpack (~> 1.2)
brakeman (7.0.2)
racc
builder (3.3.0)
capybara (3.40.0)
addressable
matrix
mini_mime (>= 0.1.3)
nokogiri (~> 1.11)
rack (>= 1.6.0)
rack-test (>= 0.6.3)
regexp_parser (>= 1.5, < 3.0)
xpath (~> 3.2)
concurrent-ruby (1.3.5)
connection_pool (2.5.0)
crass (1.0.6)
date (3.4.1)
debug (1.10.0)
irb (~> 1.10)
reline (>= 0.3.8)
dotenv (3.1.7)
drb (2.2.1)
ed25519 (1.3.0)
erubi (1.13.1)
et-orbi (1.2.11)
tzinfo
fugit (1.11.1)
et-orbi (~> 1, >= 1.2.11)
raabro (~> 1.4)
globalid (1.2.1)
activesupport (>= 6.1)
i18n (1.14.7)
concurrent-ruby (~> 1.0)
importmap-rails (2.1.0)
actionpack (>= 6.0.0)
activesupport (>= 6.0.0)
railties (>= 6.0.0)
io-console (0.8.0)
irb (1.15.2)
pp (>= 0.6.0)
rdoc (>= 4.0.0)
reline (>= 0.4.2)
jbuilder (2.13.0)
actionview (>= 5.0.0)
activesupport (>= 5.0.0)
json (2.10.2)
kamal (2.5.3)
activesupport (>= 7.0)
base64 (~> 0.2)
bcrypt_pbkdf (~> 1.0)
concurrent-ruby (~> 1.2)
dotenv (~> 3.1)
ed25519 (~> 1.2)
net-ssh (~> 7.3)
sshkit (>= 1.23.0, < 2.0)
thor (~> 1.3)
zeitwerk (>= 2.6.18, < 3.0)
language_server-protocol (3.17.0.4)
lint_roller (1.1.0)
logger (1.7.0)
loofah (2.24.0)
crass (~> 1.0.2)
nokogiri (>= 1.12.0)
mail (2.8.1)
mini_mime (>= 0.1.1)
net-imap
net-pop
net-smtp
marcel (1.0.4)
matrix (0.4.2)
mini_mime (1.1.5)
minitest (5.25.5)
msgpack (1.8.0)
net-imap (0.5.6)
date
net-protocol
net-pop (0.1.2)
net-protocol
net-protocol (0.2.2)
timeout
net-scp (4.1.0)
net-ssh (>= 2.6.5, < 8.0.0)
net-sftp (4.0.0)
net-ssh (>= 5.0.0, < 8.0.0)
net-smtp (0.5.1)
net-protocol
net-ssh (7.3.0)
nio4r (2.7.4)
nokogiri (1.18.7-aarch64-linux-gnu)
racc (~> 1.4)
nokogiri (1.18.7-aarch64-linux-musl)
racc (~> 1.4)
nokogiri (1.18.7-arm-linux-gnu)
racc (~> 1.4)
nokogiri (1.18.7-arm-linux-musl)
racc (~> 1.4)
nokogiri (1.18.7-x86_64-linux-gnu)
racc (~> 1.4)
nokogiri (1.18.7-x86_64-linux-musl)
racc (~> 1.4)
ostruct (0.6.1)
parallel (1.26.3)
parser (3.3.7.4)
ast (~> 2.4.1)
racc
pp (0.6.2)
prettyprint
prettyprint (0.2.0)
prism (1.4.0)
propshaft (1.1.0)
actionpack (>= 7.0.0)
activesupport (>= 7.0.0)
rack
railties (>= 7.0.0)
psych (5.2.3)
date
stringio
public_suffix (6.0.1)
puma (6.6.0)
nio4r (~> 2.0)
raabro (1.4.0)
racc (1.8.1)
rack (3.1.12)
rack-session (2.1.0)
base64 (>= 0.1.0)
rack (>= 3.0.0)
rack-test (2.2.0)
rack (>= 1.3)
rackup (2.2.1)
rack (>= 3)
rails (8.0.2)
actioncable (= 8.0.2)
actionmailbox (= 8.0.2)
actionmailer (= 8.0.2)
actionpack (= 8.0.2)
actiontext (= 8.0.2)
actionview (= 8.0.2)
activejob (= 8.0.2)
activemodel (= 8.0.2)
activerecord (= 8.0.2)
activestorage (= 8.0.2)
activesupport (= 8.0.2)
bundler (>= 1.15.0)
railties (= 8.0.2)
rails-dom-testing (2.2.0)
activesupport (>= 5.0.0)
minitest
nokogiri (>= 1.6)
rails-html-sanitizer (1.6.2)
loofah (~> 2.21)
nokogiri (>= 1.15.7, != 1.16.7, != 1.16.6, != 1.16.5, != 1.16.4, != 1.16.3, != 1.16.2, != 1.16.1, != 1.16.0.rc1, != 1.16.0)
railties (8.0.2)
actionpack (= 8.0.2)
activesupport (= 8.0.2)
irb (~> 1.13)
rackup (>= 1.0.0)
rake (>= 12.2)
thor (~> 1.0, >= 1.2.2)
zeitwerk (~> 2.6)
rainbow (3.1.1)
rake (13.2.1)
rdoc (6.13.1)
psych (>= 4.0.0)
regexp_parser (2.10.0)
reline (0.6.1)
io-console (~> 0.5)
rexml (3.4.1)
rubocop (1.75.2)
json (~> 2.3)
language_server-protocol (~> 3.17.0.2)
lint_roller (~> 1.1.0)
parallel (~> 1.10)
parser (>= 3.3.0.2)
rainbow (>= 2.2.2, < 4.0)
regexp_parser (>= 2.9.3, < 3.0)
rubocop-ast (>= 1.44.0, < 2.0)
ruby-progressbar (~> 1.7)
unicode-display_width (>= 2.4.0, < 4.0)
rubocop-ast (1.44.0)
parser (>= 3.3.7.2)
prism (~> 1.4)
rubocop-performance (1.25.0)
lint_roller (~> 1.1)
rubocop (>= 1.75.0, < 2.0)
rubocop-ast (>= 1.38.0, < 2.0)
rubocop-rails (2.31.0)
activesupport (>= 4.2.0)
lint_roller (~> 1.1)
rack (>= 1.1)
rubocop (>= 1.75.0, < 2.0)
rubocop-ast (>= 1.38.0, < 2.0)
rubocop-rails-omakase (1.1.0)
rubocop (>= 1.72)
rubocop-performance (>= 1.24)
rubocop-rails (>= 2.30)
ruby-progressbar (1.13.0)
rubyzip (2.4.1)
securerandom (0.4.1)
selenium-webdriver (4.31.0)
base64 (~> 0.2)
logger (~> 1.4)
rexml (~> 3.2, >= 3.2.5)
rubyzip (>= 1.2.2, < 3.0)
websocket (~> 1.0)
solid_cable (3.0.7)
actioncable (>= 7.2)
activejob (>= 7.2)
activerecord (>= 7.2)
railties (>= 7.2)
solid_cache (1.0.7)
activejob (>= 7.2)
activerecord (>= 7.2)
railties (>= 7.2)
solid_queue (1.1.4)
activejob (>= 7.1)
activerecord (>= 7.1)
concurrent-ruby (>= 1.3.1)
fugit (~> 1.11.0)
railties (>= 7.1)
thor (~> 1.3.1)
sqlite3 (2.6.0-aarch64-linux-gnu)
sqlite3 (2.6.0-aarch64-linux-musl)
sqlite3 (2.6.0-arm-linux-gnu)
sqlite3 (2.6.0-arm-linux-musl)
sqlite3 (2.6.0-x86_64-linux-gnu)
sqlite3 (2.6.0-x86_64-linux-musl)
sshkit (1.24.0)
base64
logger
net-scp (>= 1.1.2)
net-sftp (>= 2.1.2)
net-ssh (>= 2.8.0)
ostruct
stimulus-rails (1.3.4)
railties (>= 6.0.0)
stringio (3.1.6)
thor (1.3.2)
thruster (0.1.12)
thruster (0.1.12-aarch64-linux)
thruster (0.1.12-x86_64-linux)
timeout (0.4.3)
turbo-rails (2.0.13)
actionpack (>= 7.1.0)
railties (>= 7.1.0)
tzinfo (2.0.6)
concurrent-ruby (~> 1.0)
unicode-display_width (3.1.4)
unicode-emoji (~> 4.0, >= 4.0.4)
unicode-emoji (4.0.4)
uri (1.0.3)
useragent (0.16.11)
web-console (4.2.1)
actionview (>= 6.0.0)
activemodel (>= 6.0.0)
bindex (>= 0.4.0)
railties (>= 6.0.0)
websocket (1.2.11)
websocket-driver (0.7.7)
base64
websocket-extensions (>= 0.1.0)
websocket-extensions (0.1.5)
xpath (3.2.0)
nokogiri (~> 1.8)
zeitwerk (2.7.2)
PLATFORMS
aarch64-linux
aarch64-linux-gnu
aarch64-linux-musl
arm-linux-gnu
arm-linux-musl
x86_64-linux
x86_64-linux-gnu
x86_64-linux-musl
DEPENDENCIES
bootsnap
brakeman
capybara
debug
importmap-rails
jbuilder
kamal
propshaft
puma (>= 5.0)
rails (~> 8.0.2)
rubocop-rails-omakase
selenium-webdriver
solid_cable
solid_cache
solid_queue
sqlite3 (>= 2.1)
stimulus-rails
thruster
turbo-rails
tzinfo-data
web-console
BUNDLED WITH
2.6.7
+24
View File
@@ -0,0 +1,24 @@
# README
This README would normally document whatever steps are necessary to get the
application up and running.
Things you may want to cover:
* Ruby version
* System dependencies
* Configuration
* Database creation
* Database initialization
* How to run the test suite
* Services (job queues, cache servers, search engines, etc.)
* Deployment instructions
* ...
+6
View File
@@ -0,0 +1,6 @@
# Add your own tasks in files placed in lib/tasks ending in .rake,
# for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
require_relative "config/application"
Rails.application.load_tasks
View File
@@ -0,0 +1,10 @@
/*
* This is a manifest file that'll be compiled into application.css.
*
* With Propshaft, assets are served efficiently without preprocessing steps. You can still include
* application-wide styles in this file, but keep in mind that CSS precedence will follow the standard
* cascading order, meaning styles declared later in the document or manifest will override earlier ones,
* depending on specificity.
*
* Consider organizing styles into separate files for maintainability.
*/
@@ -0,0 +1,4 @@
class ApplicationController < ActionController::Base
# Only allow modern browsers supporting webp images, web push, badges, import maps, CSS nesting, and CSS :has.
allow_browser versions: :modern
end
View File
+2
View File
@@ -0,0 +1,2 @@
module ApplicationHelper
end
+3
View File
@@ -0,0 +1,3 @@
// Configure your import map in config/importmap.rb. Read more: https://github.com/rails/importmap-rails
import "@hotwired/turbo-rails"
import "controllers"
@@ -0,0 +1,9 @@
import { Application } from "@hotwired/stimulus"
const application = Application.start()
// Configure Stimulus development experience
application.debug = false
window.Stimulus = application
export { application }
@@ -0,0 +1,7 @@
import { Controller } from "@hotwired/stimulus"
export default class extends Controller {
connect() {
this.element.textContent = "Hello World!"
}
}
+4
View File
@@ -0,0 +1,4 @@
// Import and register all your controllers from the importmap via controllers/**/*_controller
import { application } from "controllers/application"
import { eagerLoadControllersFrom } from "@hotwired/stimulus-loading"
eagerLoadControllersFrom("controllers", application)
+7
View File
@@ -0,0 +1,7 @@
class ApplicationJob < ActiveJob::Base
# Automatically retry jobs that encountered a deadlock
# retry_on ActiveRecord::Deadlocked
# Most jobs are safe to ignore if the underlying records are no longer available
# discard_on ActiveJob::DeserializationError
end
+4
View File
@@ -0,0 +1,4 @@
class ApplicationMailer < ActionMailer::Base
default from: "from@example.com"
layout "mailer"
end
+3
View File
@@ -0,0 +1,3 @@
class ApplicationRecord < ActiveRecord::Base
primary_abstract_class
end
View File
@@ -0,0 +1,28 @@
<!DOCTYPE html>
<html>
<head>
<title><%= content_for(:title) || "Ruby" %></title>
<meta name="viewport" content="width=device-width,initial-scale=1">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="mobile-web-app-capable" content="yes">
<%= csrf_meta_tags %>
<%= csp_meta_tag %>
<%= yield :head %>
<%# Enable PWA manifest for installable apps (make sure to enable in config/routes.rb too!) %>
<%#= tag.link rel: "manifest", href: pwa_manifest_path(format: :json) %>
<link rel="icon" href="/icon.png" type="image/png">
<link rel="icon" href="/icon.svg" type="image/svg+xml">
<link rel="apple-touch-icon" href="/icon.png">
<%# Includes all stylesheet files in app/assets/stylesheets %>
<%= stylesheet_link_tag :app, "data-turbo-track": "reload" %>
<%= javascript_importmap_tags %>
</head>
<body>
<%= yield %>
</body>
</html>
+13
View File
@@ -0,0 +1,13 @@
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<style>
/* Email styles need to be inline */
</style>
</head>
<body>
<%= yield %>
</body>
</html>
+1
View File
@@ -0,0 +1 @@
<%= yield %>
+22
View File
@@ -0,0 +1,22 @@
{
"name": "Ruby",
"icons": [
{
"src": "/icon.png",
"type": "image/png",
"sizes": "512x512"
},
{
"src": "/icon.png",
"type": "image/png",
"sizes": "512x512",
"purpose": "maskable"
}
],
"start_url": "/",
"display": "standalone",
"scope": "/",
"description": "Ruby.",
"theme_color": "red",
"background_color": "red"
}
+26
View File
@@ -0,0 +1,26 @@
// Add a service worker for processing Web Push notifications:
//
// self.addEventListener("push", async (event) => {
// const { title, options } = await event.data.json()
// event.waitUntil(self.registration.showNotification(title, options))
// })
//
// self.addEventListener("notificationclick", function(event) {
// event.notification.close()
// event.waitUntil(
// clients.matchAll({ type: "window" }).then((clientList) => {
// for (let i = 0; i < clientList.length; i++) {
// let client = clientList[i]
// let clientPath = (new URL(client.url)).pathname
//
// if (clientPath == event.notification.data.path && "focus" in client) {
// return client.focus()
// }
// }
//
// if (clients.openWindow) {
// return clients.openWindow(event.notification.data.path)
// }
// })
// )
// })
+7
View File
@@ -0,0 +1,7 @@
#!/usr/bin/env ruby
require "rubygems"
require "bundler/setup"
ARGV.unshift("--ensure-latest")
load Gem.bin_path("brakeman", "brakeman")
+109
View File
@@ -0,0 +1,109 @@
#!/usr/bin/env ruby
# frozen_string_literal: true
#
# This file was generated by Bundler.
#
# The application 'bundle' is installed as part of a gem, and
# this file is here to facilitate running it.
#
require "rubygems"
m = Module.new do
module_function
def invoked_as_script?
File.expand_path($0) == File.expand_path(__FILE__)
end
def env_var_version
ENV["BUNDLER_VERSION"]
end
def cli_arg_version
return unless invoked_as_script? # don't want to hijack other binstubs
return unless "update".start_with?(ARGV.first || " ") # must be running `bundle update`
bundler_version = nil
update_index = nil
ARGV.each_with_index do |a, i|
if update_index && update_index.succ == i && a.match?(Gem::Version::ANCHORED_VERSION_PATTERN)
bundler_version = a
end
next unless a =~ /\A--bundler(?:[= ](#{Gem::Version::VERSION_PATTERN}))?\z/
bundler_version = $1
update_index = i
end
bundler_version
end
def gemfile
gemfile = ENV["BUNDLE_GEMFILE"]
return gemfile if gemfile && !gemfile.empty?
File.expand_path("../Gemfile", __dir__)
end
def lockfile
lockfile =
case File.basename(gemfile)
when "gems.rb" then gemfile.sub(/\.rb$/, ".locked")
else "#{gemfile}.lock"
end
File.expand_path(lockfile)
end
def lockfile_version
return unless File.file?(lockfile)
lockfile_contents = File.read(lockfile)
return unless lockfile_contents =~ /\n\nBUNDLED WITH\n\s{2,}(#{Gem::Version::VERSION_PATTERN})\n/
Regexp.last_match(1)
end
def bundler_requirement
@bundler_requirement ||=
env_var_version ||
cli_arg_version ||
bundler_requirement_for(lockfile_version)
end
def bundler_requirement_for(version)
return "#{Gem::Requirement.default}.a" unless version
bundler_gem_version = Gem::Version.new(version)
bundler_gem_version.approximate_recommendation
end
def load_bundler!
ENV["BUNDLE_GEMFILE"] ||= gemfile
activate_bundler
end
def activate_bundler
gem_error = activation_error_handling do
gem "bundler", bundler_requirement
end
return if gem_error.nil?
require_error = activation_error_handling do
require "bundler/version"
end
return if require_error.nil? && Gem::Requirement.new(bundler_requirement).satisfied_by?(Gem::Version.new(Bundler::VERSION))
warn "Activating bundler (#{bundler_requirement}) failed:\n#{gem_error.message}\n\nTo install the version of bundler this project requires, run `gem install bundler -v '#{bundler_requirement}'`"
exit 42
end
def activation_error_handling
yield
nil
rescue StandardError, LoadError => e
e
end
end
m.load_bundler!
if m.invoked_as_script?
load Gem.bin_path("bundler", "bundle")
end
Executable
+2
View File
@@ -0,0 +1,2 @@
#!/usr/bin/env ruby
exec "./bin/rails", "server", *ARGV
+14
View File
@@ -0,0 +1,14 @@
#!/bin/bash -e
# Enable jemalloc for reduced memory usage and latency.
if [ -z "${LD_PRELOAD+x}" ]; then
LD_PRELOAD=$(find /usr/lib -name libjemalloc.so.2 -print -quit)
export LD_PRELOAD
fi
# If running the rails server then create or migrate existing database
if [ "${@: -2:1}" == "./bin/rails" ] && [ "${@: -1:1}" == "server" ]; then
./bin/rails db:prepare
fi
exec "${@}"
+4
View File
@@ -0,0 +1,4 @@
#!/usr/bin/env ruby
require_relative "../config/application"
require "importmap/commands"
Executable
+6
View File
@@ -0,0 +1,6 @@
#!/usr/bin/env ruby
require_relative "../config/environment"
require "solid_queue/cli"
SolidQueue::Cli.start(ARGV)

Some files were not shown because too many files have changed in this diff Show More