docs: Add instructions for serving the tape and generating keys

This commit is contained in:
Felicitas Pojtinger
2022-05-15 22:53:19 +02:00
parent e3b14e4264
commit 7233cd986a
8 changed files with 213 additions and 150 deletions

View File

@@ -44,9 +44,55 @@ You can find binaries for more operating systems and architectures on [GitHub re
### 1. Generating Keys with `stfs keygen`
### 2. Serving a Tape Read-Only with `stfs serve http`
While not strictly required, it is recommended to generate keys to sign and encrypt your data on tape. There are multiple methods available; `PGP` and [age](https://github.com/FiloSottile/age) for encryption, and `PGP` as well as [Minisign](https://github.com/aead/minisign) for signatures. In most cases, using age for encryption and PGP for signatures is the best option. To generate the appropriate keys, run the following; make sure to save the keys in a secure location and use a secure password:
### 3. Serving a Tape Read-Write with `stfs serve ftp`
```shell
$ stfs keygen --encryption age --password mysecureencryptionpassword --identity ~/.stfs-age.priv --recipient ~/.stfs-age.pub
$ stfs keygen --signature pgp --password mysecuresignaturepassword --identity ~/.stfs-pgp.priv --recipient ~/.stfs-pgp.pub
```
For more information, see the [key generation reference](#key-generation).
### 2. Serving a Tape Read-Write with `stfs serve ftp`
The simplest way to read or write to/from the tape (or tar file) is to use the integrated FTP server. To speed up operations, caching mechanisms and compression are available. For the write cache (`--cache-write-type`) the following types are available:
- `memory`: A simple in-memory cache; should not be used in most cases due to potential RAM exhaustion when adding large files
- `file`: A on-disk cache; this is recommended in most cases, especially if a SSD is available
For the read cache (`--cache-filesystem-type`), which is especially useful when working with many small files, similar types are available (`memory` and `dir`). `dir` uses a overlay filesystem to cache files in the directory specified with `--cache-dir`.
To further speed up IO-limited read/write operations, multiple compression options are available to be selected with `--compression` and can be tuned with `--compression-level`:
- `zstandard`: A Meta-led replacement for `gzip` with very high speeds and a very good compression ratio; this is recommended for most users
- `gzip`/`parallelgzip`: The GNU format commonly used in combination with `tar`, i.e. for `.tar.gz`; reasonably fast and with a good compression ratio
- `bzip2`/`parallelbzip2`: A reliable compression format with good speeds and a better compression ratio than `gzip`.
- `lz4`: Very fast, but at the cost of a lower compression ratio
- `brotli`: A Google-led compression format with good adoption on the web platform; very high compression ratio, very slow speeds
To serve a tape (or tar file), run the following (adjust the options accordinly):
```shell
# Use `-d /dev/nst0` for your primary tape drive instead
$ stfs serve ftp \
-d ~/Downloads/drive.tar \
-m ~/Downloads/metadata.sqlite \
-e age \
--encryption-identity ~/.stfs-age.priv \
--encryption-recipient ~/.stfs-age.pub \
--encryption-password mysecureencryptionpassword \
-s pgp \
--signature-identity ~/.stfs-pgp.priv \
--signature-recipient ~/.stfs-pgp.pub \
--signature-password mysecuresignaturepassword
{"time":1652646259,"level":"INFO","event":"FTP server listening","data":[{"laddr":":1337"}]}
{"time":1652646259,"level":"INFO","event":"Listening...","data":["address",{"IP":"::","Port":1337,"Zone":""}]}
{"time":1652646259,"level":"INFO","event":"Starting...","data":null}
```
You can now point your FTP browser (such as Nautilus on GNOME) to `ftp://localhost:1337` and read/write files from the tape (or tape file).
### 3. Serving a Tape Read-Only with `stfs serve http`
### 4. Using Optimized Operations with `stfs operation`
@@ -288,14 +334,6 @@ Use "stfs serve [command] --help" for more information about a command.
All command line arguments described above can also be set using environment variables; for example, to set `--drive` to `/tmp/drive.tar` with an environment variable, use `STFS_DRIVE=/tmp/drive.tar`.
### Caching Options
### Compression Options
### Encryption Options
### Signature Options
## Acknowledgements
- [aead.dev/minisign](https://github.com/aead/minisign) provides the Minisign signature implementation.

View File

@@ -1,4 +1,4 @@
// Code generated by SQLBoiler 4.8.3 (https://github.com/volatiletech/sqlboiler). DO NOT EDIT.
// Code generated by SQLBoiler 4.11.0 (https://github.com/volatiletech/sqlboiler). DO NOT EDIT.
// This file is meant to be re-generated in place and/or deleted at any time.
package models

View File

@@ -1,4 +1,4 @@
// Code generated by SQLBoiler 4.8.3 (https://github.com/volatiletech/sqlboiler). DO NOT EDIT.
// Code generated by SQLBoiler 4.11.0 (https://github.com/volatiletech/sqlboiler). DO NOT EDIT.
// This file is meant to be re-generated in place and/or deleted at any time.
package models

View File

@@ -1,4 +1,4 @@
// Code generated by SQLBoiler 4.8.3 (https://github.com/volatiletech/sqlboiler). DO NOT EDIT.
// Code generated by SQLBoiler 4.11.0 (https://github.com/volatiletech/sqlboiler). DO NOT EDIT.
// This file is meant to be re-generated in place and/or deleted at any time.
package models

View File

@@ -0,0 +1,7 @@
// Code generated by SQLBoiler 4.11.0 (https://github.com/volatiletech/sqlboiler). DO NOT EDIT.
// This file is meant to be re-generated in place and/or deleted at any time.
package models
var ViewNames = struct {
}{}

View File

@@ -1,4 +1,4 @@
// Code generated by SQLBoiler 4.8.3 (https://github.com/volatiletech/sqlboiler). DO NOT EDIT.
// Code generated by SQLBoiler 4.11.0 (https://github.com/volatiletech/sqlboiler). DO NOT EDIT.
// This file is meant to be re-generated in place and/or deleted at any time.
package models
@@ -125,6 +125,7 @@ var (
gorpMigrationColumnsWithoutDefault = []string{"id", "applied_at"}
gorpMigrationColumnsWithDefault = []string{}
gorpMigrationPrimaryKeyColumns = []string{"id"}
gorpMigrationGeneratedColumns = []string{}
)
type (
@@ -160,17 +161,35 @@ var (
_ = qmhelper.Where
)
var gorpMigrationBeforeInsertHooks []GorpMigrationHook
var gorpMigrationBeforeUpdateHooks []GorpMigrationHook
var gorpMigrationBeforeDeleteHooks []GorpMigrationHook
var gorpMigrationBeforeUpsertHooks []GorpMigrationHook
var gorpMigrationAfterInsertHooks []GorpMigrationHook
var gorpMigrationAfterSelectHooks []GorpMigrationHook
var gorpMigrationBeforeInsertHooks []GorpMigrationHook
var gorpMigrationAfterInsertHooks []GorpMigrationHook
var gorpMigrationBeforeUpdateHooks []GorpMigrationHook
var gorpMigrationAfterUpdateHooks []GorpMigrationHook
var gorpMigrationBeforeDeleteHooks []GorpMigrationHook
var gorpMigrationAfterDeleteHooks []GorpMigrationHook
var gorpMigrationBeforeUpsertHooks []GorpMigrationHook
var gorpMigrationAfterUpsertHooks []GorpMigrationHook
// doAfterSelectHooks executes all "after Select" hooks.
func (o *GorpMigration) doAfterSelectHooks(ctx context.Context, exec boil.ContextExecutor) (err error) {
if boil.HooksAreSkipped(ctx) {
return nil
}
for _, hook := range gorpMigrationAfterSelectHooks {
if err := hook(ctx, exec, o); err != nil {
return err
}
}
return nil
}
// doBeforeInsertHooks executes all "before insert" hooks.
func (o *GorpMigration) doBeforeInsertHooks(ctx context.Context, exec boil.ContextExecutor) (err error) {
if boil.HooksAreSkipped(ctx) {
@@ -186,51 +205,6 @@ func (o *GorpMigration) doBeforeInsertHooks(ctx context.Context, exec boil.Conte
return nil
}
// doBeforeUpdateHooks executes all "before Update" hooks.
func (o *GorpMigration) doBeforeUpdateHooks(ctx context.Context, exec boil.ContextExecutor) (err error) {
if boil.HooksAreSkipped(ctx) {
return nil
}
for _, hook := range gorpMigrationBeforeUpdateHooks {
if err := hook(ctx, exec, o); err != nil {
return err
}
}
return nil
}
// doBeforeDeleteHooks executes all "before Delete" hooks.
func (o *GorpMigration) doBeforeDeleteHooks(ctx context.Context, exec boil.ContextExecutor) (err error) {
if boil.HooksAreSkipped(ctx) {
return nil
}
for _, hook := range gorpMigrationBeforeDeleteHooks {
if err := hook(ctx, exec, o); err != nil {
return err
}
}
return nil
}
// doBeforeUpsertHooks executes all "before Upsert" hooks.
func (o *GorpMigration) doBeforeUpsertHooks(ctx context.Context, exec boil.ContextExecutor) (err error) {
if boil.HooksAreSkipped(ctx) {
return nil
}
for _, hook := range gorpMigrationBeforeUpsertHooks {
if err := hook(ctx, exec, o); err != nil {
return err
}
}
return nil
}
// doAfterInsertHooks executes all "after Insert" hooks.
func (o *GorpMigration) doAfterInsertHooks(ctx context.Context, exec boil.ContextExecutor) (err error) {
if boil.HooksAreSkipped(ctx) {
@@ -246,13 +220,13 @@ func (o *GorpMigration) doAfterInsertHooks(ctx context.Context, exec boil.Contex
return nil
}
// doAfterSelectHooks executes all "after Select" hooks.
func (o *GorpMigration) doAfterSelectHooks(ctx context.Context, exec boil.ContextExecutor) (err error) {
// doBeforeUpdateHooks executes all "before Update" hooks.
func (o *GorpMigration) doBeforeUpdateHooks(ctx context.Context, exec boil.ContextExecutor) (err error) {
if boil.HooksAreSkipped(ctx) {
return nil
}
for _, hook := range gorpMigrationAfterSelectHooks {
for _, hook := range gorpMigrationBeforeUpdateHooks {
if err := hook(ctx, exec, o); err != nil {
return err
}
@@ -276,6 +250,21 @@ func (o *GorpMigration) doAfterUpdateHooks(ctx context.Context, exec boil.Contex
return nil
}
// doBeforeDeleteHooks executes all "before Delete" hooks.
func (o *GorpMigration) doBeforeDeleteHooks(ctx context.Context, exec boil.ContextExecutor) (err error) {
if boil.HooksAreSkipped(ctx) {
return nil
}
for _, hook := range gorpMigrationBeforeDeleteHooks {
if err := hook(ctx, exec, o); err != nil {
return err
}
}
return nil
}
// doAfterDeleteHooks executes all "after Delete" hooks.
func (o *GorpMigration) doAfterDeleteHooks(ctx context.Context, exec boil.ContextExecutor) (err error) {
if boil.HooksAreSkipped(ctx) {
@@ -291,6 +280,21 @@ func (o *GorpMigration) doAfterDeleteHooks(ctx context.Context, exec boil.Contex
return nil
}
// doBeforeUpsertHooks executes all "before Upsert" hooks.
func (o *GorpMigration) doBeforeUpsertHooks(ctx context.Context, exec boil.ContextExecutor) (err error) {
if boil.HooksAreSkipped(ctx) {
return nil
}
for _, hook := range gorpMigrationBeforeUpsertHooks {
if err := hook(ctx, exec, o); err != nil {
return err
}
}
return nil
}
// doAfterUpsertHooks executes all "after Upsert" hooks.
func (o *GorpMigration) doAfterUpsertHooks(ctx context.Context, exec boil.ContextExecutor) (err error) {
if boil.HooksAreSkipped(ctx) {
@@ -309,22 +313,22 @@ func (o *GorpMigration) doAfterUpsertHooks(ctx context.Context, exec boil.Contex
// AddGorpMigrationHook registers your hook function for all future operations.
func AddGorpMigrationHook(hookPoint boil.HookPoint, gorpMigrationHook GorpMigrationHook) {
switch hookPoint {
case boil.BeforeInsertHook:
gorpMigrationBeforeInsertHooks = append(gorpMigrationBeforeInsertHooks, gorpMigrationHook)
case boil.BeforeUpdateHook:
gorpMigrationBeforeUpdateHooks = append(gorpMigrationBeforeUpdateHooks, gorpMigrationHook)
case boil.BeforeDeleteHook:
gorpMigrationBeforeDeleteHooks = append(gorpMigrationBeforeDeleteHooks, gorpMigrationHook)
case boil.BeforeUpsertHook:
gorpMigrationBeforeUpsertHooks = append(gorpMigrationBeforeUpsertHooks, gorpMigrationHook)
case boil.AfterInsertHook:
gorpMigrationAfterInsertHooks = append(gorpMigrationAfterInsertHooks, gorpMigrationHook)
case boil.AfterSelectHook:
gorpMigrationAfterSelectHooks = append(gorpMigrationAfterSelectHooks, gorpMigrationHook)
case boil.BeforeInsertHook:
gorpMigrationBeforeInsertHooks = append(gorpMigrationBeforeInsertHooks, gorpMigrationHook)
case boil.AfterInsertHook:
gorpMigrationAfterInsertHooks = append(gorpMigrationAfterInsertHooks, gorpMigrationHook)
case boil.BeforeUpdateHook:
gorpMigrationBeforeUpdateHooks = append(gorpMigrationBeforeUpdateHooks, gorpMigrationHook)
case boil.AfterUpdateHook:
gorpMigrationAfterUpdateHooks = append(gorpMigrationAfterUpdateHooks, gorpMigrationHook)
case boil.BeforeDeleteHook:
gorpMigrationBeforeDeleteHooks = append(gorpMigrationBeforeDeleteHooks, gorpMigrationHook)
case boil.AfterDeleteHook:
gorpMigrationAfterDeleteHooks = append(gorpMigrationAfterDeleteHooks, gorpMigrationHook)
case boil.BeforeUpsertHook:
gorpMigrationBeforeUpsertHooks = append(gorpMigrationBeforeUpsertHooks, gorpMigrationHook)
case boil.AfterUpsertHook:
gorpMigrationAfterUpsertHooks = append(gorpMigrationAfterUpsertHooks, gorpMigrationHook)
}
@@ -338,7 +342,7 @@ func (q gorpMigrationQuery) One(ctx context.Context, exec boil.ContextExecutor)
err := q.Bind(ctx, exec, o)
if err != nil {
if errors.Cause(err) == sql.ErrNoRows {
if errors.Is(err, sql.ErrNoRows) {
return nil, sql.ErrNoRows
}
return nil, errors.Wrap(err, "models: failed to execute a one query for gorp_migrations")
@@ -405,7 +409,12 @@ func (q gorpMigrationQuery) Exists(ctx context.Context, exec boil.ContextExecuto
// GorpMigrations retrieves all the records using an executor.
func GorpMigrations(mods ...qm.QueryMod) gorpMigrationQuery {
mods = append(mods, qm.From("\"gorp_migrations\""))
return gorpMigrationQuery{NewQuery(mods...)}
q := NewQuery(mods...)
if len(queries.GetSelect(q)) == 0 {
queries.SetSelect(q, []string{"\"gorp_migrations\".*"})
}
return gorpMigrationQuery{q}
}
// FindGorpMigration retrieves a single record by ID with an executor.
@@ -425,7 +434,7 @@ func FindGorpMigration(ctx context.Context, exec boil.ContextExecutor, iD string
err := q.Bind(ctx, exec, gorpMigrationObj)
if err != nil {
if errors.Cause(err) == sql.ErrNoRows {
if errors.Is(err, sql.ErrNoRows) {
return nil, sql.ErrNoRows
}
return nil, errors.Wrap(err, "models: unable to select from gorp_migrations")

View File

@@ -1,4 +1,4 @@
// Code generated by SQLBoiler 4.8.3 (https://github.com/volatiletech/sqlboiler). DO NOT EDIT.
// Code generated by SQLBoiler 4.11.0 (https://github.com/volatiletech/sqlboiler). DO NOT EDIT.
// This file is meant to be re-generated in place and/or deleted at any time.
package models
@@ -254,6 +254,7 @@ var (
headerColumnsWithoutDefault = []string{"record", "lastknownrecord", "block", "lastknownblock", "deleted", "typeflag", "name", "linkname", "size", "mode", "uid", "gid", "uname", "gname", "modtime", "accesstime", "changetime", "devmajor", "devminor", "paxrecords", "format"}
headerColumnsWithDefault = []string{}
headerPrimaryKeyColumns = []string{"name", "linkname"}
headerGeneratedColumns = []string{}
)
type (
@@ -289,17 +290,35 @@ var (
_ = qmhelper.Where
)
var headerBeforeInsertHooks []HeaderHook
var headerBeforeUpdateHooks []HeaderHook
var headerBeforeDeleteHooks []HeaderHook
var headerBeforeUpsertHooks []HeaderHook
var headerAfterInsertHooks []HeaderHook
var headerAfterSelectHooks []HeaderHook
var headerBeforeInsertHooks []HeaderHook
var headerAfterInsertHooks []HeaderHook
var headerBeforeUpdateHooks []HeaderHook
var headerAfterUpdateHooks []HeaderHook
var headerBeforeDeleteHooks []HeaderHook
var headerAfterDeleteHooks []HeaderHook
var headerBeforeUpsertHooks []HeaderHook
var headerAfterUpsertHooks []HeaderHook
// doAfterSelectHooks executes all "after Select" hooks.
func (o *Header) doAfterSelectHooks(ctx context.Context, exec boil.ContextExecutor) (err error) {
if boil.HooksAreSkipped(ctx) {
return nil
}
for _, hook := range headerAfterSelectHooks {
if err := hook(ctx, exec, o); err != nil {
return err
}
}
return nil
}
// doBeforeInsertHooks executes all "before insert" hooks.
func (o *Header) doBeforeInsertHooks(ctx context.Context, exec boil.ContextExecutor) (err error) {
if boil.HooksAreSkipped(ctx) {
@@ -315,51 +334,6 @@ func (o *Header) doBeforeInsertHooks(ctx context.Context, exec boil.ContextExecu
return nil
}
// doBeforeUpdateHooks executes all "before Update" hooks.
func (o *Header) doBeforeUpdateHooks(ctx context.Context, exec boil.ContextExecutor) (err error) {
if boil.HooksAreSkipped(ctx) {
return nil
}
for _, hook := range headerBeforeUpdateHooks {
if err := hook(ctx, exec, o); err != nil {
return err
}
}
return nil
}
// doBeforeDeleteHooks executes all "before Delete" hooks.
func (o *Header) doBeforeDeleteHooks(ctx context.Context, exec boil.ContextExecutor) (err error) {
if boil.HooksAreSkipped(ctx) {
return nil
}
for _, hook := range headerBeforeDeleteHooks {
if err := hook(ctx, exec, o); err != nil {
return err
}
}
return nil
}
// doBeforeUpsertHooks executes all "before Upsert" hooks.
func (o *Header) doBeforeUpsertHooks(ctx context.Context, exec boil.ContextExecutor) (err error) {
if boil.HooksAreSkipped(ctx) {
return nil
}
for _, hook := range headerBeforeUpsertHooks {
if err := hook(ctx, exec, o); err != nil {
return err
}
}
return nil
}
// doAfterInsertHooks executes all "after Insert" hooks.
func (o *Header) doAfterInsertHooks(ctx context.Context, exec boil.ContextExecutor) (err error) {
if boil.HooksAreSkipped(ctx) {
@@ -375,13 +349,13 @@ func (o *Header) doAfterInsertHooks(ctx context.Context, exec boil.ContextExecut
return nil
}
// doAfterSelectHooks executes all "after Select" hooks.
func (o *Header) doAfterSelectHooks(ctx context.Context, exec boil.ContextExecutor) (err error) {
// doBeforeUpdateHooks executes all "before Update" hooks.
func (o *Header) doBeforeUpdateHooks(ctx context.Context, exec boil.ContextExecutor) (err error) {
if boil.HooksAreSkipped(ctx) {
return nil
}
for _, hook := range headerAfterSelectHooks {
for _, hook := range headerBeforeUpdateHooks {
if err := hook(ctx, exec, o); err != nil {
return err
}
@@ -405,6 +379,21 @@ func (o *Header) doAfterUpdateHooks(ctx context.Context, exec boil.ContextExecut
return nil
}
// doBeforeDeleteHooks executes all "before Delete" hooks.
func (o *Header) doBeforeDeleteHooks(ctx context.Context, exec boil.ContextExecutor) (err error) {
if boil.HooksAreSkipped(ctx) {
return nil
}
for _, hook := range headerBeforeDeleteHooks {
if err := hook(ctx, exec, o); err != nil {
return err
}
}
return nil
}
// doAfterDeleteHooks executes all "after Delete" hooks.
func (o *Header) doAfterDeleteHooks(ctx context.Context, exec boil.ContextExecutor) (err error) {
if boil.HooksAreSkipped(ctx) {
@@ -420,6 +409,21 @@ func (o *Header) doAfterDeleteHooks(ctx context.Context, exec boil.ContextExecut
return nil
}
// doBeforeUpsertHooks executes all "before Upsert" hooks.
func (o *Header) doBeforeUpsertHooks(ctx context.Context, exec boil.ContextExecutor) (err error) {
if boil.HooksAreSkipped(ctx) {
return nil
}
for _, hook := range headerBeforeUpsertHooks {
if err := hook(ctx, exec, o); err != nil {
return err
}
}
return nil
}
// doAfterUpsertHooks executes all "after Upsert" hooks.
func (o *Header) doAfterUpsertHooks(ctx context.Context, exec boil.ContextExecutor) (err error) {
if boil.HooksAreSkipped(ctx) {
@@ -438,22 +442,22 @@ func (o *Header) doAfterUpsertHooks(ctx context.Context, exec boil.ContextExecut
// AddHeaderHook registers your hook function for all future operations.
func AddHeaderHook(hookPoint boil.HookPoint, headerHook HeaderHook) {
switch hookPoint {
case boil.BeforeInsertHook:
headerBeforeInsertHooks = append(headerBeforeInsertHooks, headerHook)
case boil.BeforeUpdateHook:
headerBeforeUpdateHooks = append(headerBeforeUpdateHooks, headerHook)
case boil.BeforeDeleteHook:
headerBeforeDeleteHooks = append(headerBeforeDeleteHooks, headerHook)
case boil.BeforeUpsertHook:
headerBeforeUpsertHooks = append(headerBeforeUpsertHooks, headerHook)
case boil.AfterInsertHook:
headerAfterInsertHooks = append(headerAfterInsertHooks, headerHook)
case boil.AfterSelectHook:
headerAfterSelectHooks = append(headerAfterSelectHooks, headerHook)
case boil.BeforeInsertHook:
headerBeforeInsertHooks = append(headerBeforeInsertHooks, headerHook)
case boil.AfterInsertHook:
headerAfterInsertHooks = append(headerAfterInsertHooks, headerHook)
case boil.BeforeUpdateHook:
headerBeforeUpdateHooks = append(headerBeforeUpdateHooks, headerHook)
case boil.AfterUpdateHook:
headerAfterUpdateHooks = append(headerAfterUpdateHooks, headerHook)
case boil.BeforeDeleteHook:
headerBeforeDeleteHooks = append(headerBeforeDeleteHooks, headerHook)
case boil.AfterDeleteHook:
headerAfterDeleteHooks = append(headerAfterDeleteHooks, headerHook)
case boil.BeforeUpsertHook:
headerBeforeUpsertHooks = append(headerBeforeUpsertHooks, headerHook)
case boil.AfterUpsertHook:
headerAfterUpsertHooks = append(headerAfterUpsertHooks, headerHook)
}
@@ -467,7 +471,7 @@ func (q headerQuery) One(ctx context.Context, exec boil.ContextExecutor) (*Heade
err := q.Bind(ctx, exec, o)
if err != nil {
if errors.Cause(err) == sql.ErrNoRows {
if errors.Is(err, sql.ErrNoRows) {
return nil, sql.ErrNoRows
}
return nil, errors.Wrap(err, "models: failed to execute a one query for headers")
@@ -534,7 +538,12 @@ func (q headerQuery) Exists(ctx context.Context, exec boil.ContextExecutor) (boo
// Headers retrieves all the records using an executor.
func Headers(mods ...qm.QueryMod) headerQuery {
mods = append(mods, qm.From("\"headers\""))
return headerQuery{NewQuery(mods...)}
q := NewQuery(mods...)
if len(queries.GetSelect(q)) == 0 {
queries.SetSelect(q, []string{"\"headers\".*"})
}
return headerQuery{q}
}
// FindHeader retrieves a single record by ID with an executor.
@@ -554,7 +563,7 @@ func FindHeader(ctx context.Context, exec boil.ContextExecutor, name string, lin
err := q.Bind(ctx, exec, headerObj)
if err != nil {
if errors.Cause(err) == sql.ErrNoRows {
if errors.Is(err, sql.ErrNoRows) {
return nil, sql.ErrNoRows
}
return nil, errors.Wrap(err, "models: unable to select from headers")

View File

@@ -1,4 +1,4 @@
// Code generated by SQLBoiler 4.8.3 (https://github.com/volatiletech/sqlboiler). DO NOT EDIT.
// Code generated by SQLBoiler 4.11.0 (https://github.com/volatiletech/sqlboiler). DO NOT EDIT.
// This file is meant to be re-generated in place and/or deleted at any time.
package models