5 Commits
v1.0 ... v1.0.1

Author SHA1 Message Date
984752b812 remove unused archs
I am not using nor need arm64 and windows. Removing these from the
Makefile. If you see this message and feel like they should be added
back (or different archs), ping me.
2021-08-25 08:57:10 +03:00
4568429a69 main.go: remove file if on Flatten(..) failure
When a Flatten() fails, the main program used to leave an incomplete
file (usually zero-length). Now it will clean itself up on failure.
2021-08-25 08:49:30 +03:00
6f40bc91be simplify linter 2021-08-24 17:23:31 +03:00
63d171007e shellcheck 2021-08-24 16:44:58 +03:00
5d4d6410da remove windows/arm64
not available on go 1.16
2021-08-24 14:50:30 +03:00
6 changed files with 91 additions and 40 deletions

View File

@@ -3,6 +3,7 @@ packages:
- go - go
- git - git
- make - make
- shellcheck
sources: sources:
- https://git.sr.ht/~motiejus/undocker - https://git.sr.ht/~motiejus/undocker
tasks: tasks:

View File

@@ -1,44 +1,36 @@
SCRIPTS = $(shell awk '/#!\/bin\/(ba)?sh/&&FNR==1{print FILENAME}' $(shell git ls-files))
GODEPS = $(shell git ls-files '*.go' go.mod go.sum) GODEPS = $(shell git ls-files '*.go' go.mod go.sum)
GOBIN = $(shell go env GOPATH)/bin/ GOBIN = $(shell go env GOPATH)/bin/
GOOSARCHS = $(sort darwin/amd64 linux/amd64)
GOOSARCHS = $(sort \
darwin/amd64 \
darwin/arm64 \
linux/amd64 \
linux/arm64 \
windows/amd64/.exe \
windows/arm64/.exe)
VSN ?= $(shell git describe --dirty) VSN ?= $(shell git describe --dirty)
VSNHASH = $(shell git rev-parse --verify HEAD) VSNHASH = $(shell git rev-parse --verify HEAD)
LDFLAGS = -ldflags "-X main.Version=$(VSN) -X main.VersionHash=$(VSNHASH)" LDFLAGS = -ldflags "-X main.Version=$(VSN) -X main.VersionHash=$(VSNHASH)"
undocker: ## builds binary for the current architecture
CGO_ENABLED=0 go build $(LDFLAGS) -o $@
.PHONY: test .PHONY: test
test: test:
go test -race -cover ./... go test -race -cover ./...
define undockertarget define undockertarget
UNDOCKERS += undocker-$(1)-$(2)-$(VSN)$(firstword $(3)) UNDOCKERS += undocker-$(1)-$(2)-$(VSN)
undocker-$(1)-$(2)-$(VSN)$(firstword $(3)): $(GODEPS) undocker-$(1)-$(2)-$(VSN): $(GODEPS)
CGO_ENABLED=0 GOOS=$(1) GOARCH=$(2) go build $(LDFLAGS) -o $$@ CGO_ENABLED=0 GOOS=$(1) GOARCH=$(2) go build $(LDFLAGS) -o $$@
endef endef
$(foreach goosarch,$(GOOSARCHS),\ $(foreach goosarch,$(GOOSARCHS),\
$(eval $(call undockertarget,$(word 1,$(subst /, ,$(goosarch))),$(word 2,$(subst /, ,$(goosarch))),$(word 3,$(subst /, ,$(goosarch)))))) $(eval $(call undockertarget,$(word 1,$(subst /, ,$(goosarch))),$(word 2,$(subst /, ,$(goosarch))))))
.PHONY: all .PHONY: all
all: $(UNDOCKERS) all: $(UNDOCKERS)
.PHONY: lint .PHONY: lint
lint: vet staticcheck lint:
.PHONY: vet
vet:
go vet ./... go vet ./...
.PHONY: staticcheck
staticcheck:
$(GOBIN)staticcheck -f stylish ./... $(GOBIN)staticcheck -f stylish ./...
shellcheck $(SCRIPTS)
.INTERMEDIATE: coverage.out .INTERMEDIATE: coverage.out
coverage.out: $(GODEPS) coverage.out: $(GODEPS)

View File

@@ -20,6 +20,19 @@ systemd, FreeBSD Jails, and many others.
Undocker has no dependencies outside Golang stdlib. Undocker has no dependencies outside Golang stdlib.
Installation
------------
We recommend using [officially released binaries][3]. To build the project
instead, run:
```
$ make undocker
```
The number of officially released binaries is quite limited. If you'd like me
to expand a list, please contribute a patch to the Makefile.
Usage: convert docker image to rootfs Usage: convert docker image to rootfs
------------------------------------- -------------------------------------
@@ -107,3 +120,4 @@ MIT
[1]: https://www.freedesktop.org/software/systemd/man/systemd.exec.html [1]: https://www.freedesktop.org/software/systemd/man/systemd.exec.html
[2]: https://fly.io/blog/docker-without-docker/ [2]: https://fly.io/blog/docker-without-docker/
[3]: http://git.sr.ht/~motiejus/undocker

16
main.go
View File

@@ -53,15 +53,15 @@ type command struct {
Stdout io.Writer Stdout io.Writer
} }
func (c *command) execute(infile string, outfile string) (err error) { func (c *command) execute(infile string, outfile string) (_err error) {
rd, err := os.Open(infile) rd, err := os.Open(infile)
if err != nil { if err != nil {
return err return err
} }
defer func() { defer func() {
err1 := rd.Close() err := rd.Close()
if err == nil { if _err == nil {
err = err1 _err = err
} }
}() }()
@@ -74,9 +74,11 @@ func (c *command) execute(infile string, outfile string) (err error) {
return fmt.Errorf("create: %w", err) return fmt.Errorf("create: %w", err)
} }
defer func() { defer func() {
err1 := outf.Close() err := outf.Close()
if err == nil { if _err != nil {
err = err1 os.Remove(outfile)
} else {
_err = err
} }
}() }()
out = outf out = outf

View File

@@ -2,8 +2,10 @@ package main
import ( import (
"bytes" "bytes"
"errors"
"io" "io"
"io/ioutil" "io/ioutil"
"os"
"path/filepath" "path/filepath"
"regexp" "regexp"
"testing" "testing"
@@ -13,11 +15,13 @@ func TestExecute(t *testing.T) {
var _foo = []byte("foo foo") var _foo = []byte("foo foo")
tests := []struct { tests := []struct {
name string name string
fixture func(*testing.T, string) fixture func(*testing.T, string)
infile string flattener func(io.ReadSeeker, io.Writer) error
outfile string infile string
wantErr string outfile string
wantErr string
assertion func(*testing.T, string)
}{ }{
{ {
name: "ok passthrough via stdout", name: "ok passthrough via stdout",
@@ -41,6 +45,31 @@ func TestExecute(t *testing.T) {
}, },
outfile: "t20-out.txt", outfile: "t20-out.txt",
}, },
{
name: "bad flattener should remove the file",
infile: "t30-in.txt",
fixture: func(t *testing.T, dir string) {
fname := filepath.Join(dir, "t30-in.txt")
if err := ioutil.WriteFile(fname, _foo, 0644); err != nil {
t.Fatalf("unexpected error: %v", err)
}
},
flattener: flattenBad,
outfile: "t30-out.txt",
wantErr: "some error",
assertion: func(t *testing.T, dir string) {
d, err := os.ReadDir(dir)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if len(d) != 1 {
t.Fatalf("expected 1 entry, got %d", len(d))
}
if d[0].Name() != "t30-in.txt" {
t.Fatalf("expected to find only t30-in.txt, got %s", d[0].Name())
}
},
},
{ {
name: "infile does not exist", name: "infile does not exist",
infile: "t3-does-not-exist.txt", infile: "t3-does-not-exist.txt",
@@ -57,7 +86,10 @@ func TestExecute(t *testing.T) {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
dir := t.TempDir() dir := t.TempDir()
var stdout bytes.Buffer var stdout bytes.Buffer
c := &command{Stdout: &stdout} if tt.flattener == nil {
tt.flattener = flattenPassthrough
}
if tt.fixture != nil { if tt.fixture != nil {
tt.fixture(t, dir) tt.fixture(t, dir)
} }
@@ -65,9 +97,14 @@ func TestExecute(t *testing.T) {
tt.outfile = filepath.Join(dir, tt.outfile) tt.outfile = filepath.Join(dir, tt.outfile)
} }
inf := filepath.Join(dir, tt.infile) inf := filepath.Join(dir, tt.infile)
c.flattener = flattenPassthrough
c := &command{Stdout: &stdout, flattener: tt.flattener}
err := c.execute(inf, tt.outfile) err := c.execute(inf, tt.outfile)
if tt.assertion != nil {
tt.assertion(t, dir)
}
if tt.wantErr != "" { if tt.wantErr != "" {
if err == nil { if err == nil {
t.Fatal("expected error, got nil") t.Fatal("expected error, got nil")
@@ -78,10 +115,10 @@ func TestExecute(t *testing.T) {
} }
return return
} }
var out []byte
if err != nil { if err != nil {
t.Fatalf("unexpected error: %v", err) t.Fatalf("unexpected error: %v", err)
} }
var out []byte
if tt.outfile == "-" { if tt.outfile == "-" {
out = stdout.Bytes() out = stdout.Bytes()
} else { } else {
@@ -91,8 +128,9 @@ func TestExecute(t *testing.T) {
} }
} }
if !bytes.Equal([]byte("foo foo"), out) { if !bytes.Equal([]byte("foo foo"), out) {
t.Errorf("out != foo foo: %s", string(out)) t.Errorf("out != foo foo: %q", string(out))
} }
}) })
} }
} }
@@ -101,3 +139,7 @@ func flattenPassthrough(r io.ReadSeeker, w io.Writer) error {
_, err := io.Copy(w, r) _, err := io.Copy(w, r)
return err return err
} }
func flattenBad(_ io.ReadSeeker, _ io.Writer) error {
return errors.New("some error")
}

12
release
View File

@@ -6,24 +6,24 @@ err() {
exit 1 exit 1
} }
[[ -n "$(git status --porcelain)" ]] && \ git status --porcelain | grep -q "" &&
err "working tree is dirty, commit your changes first." err "working tree is dirty, commit your changes first."
[[ ! "$1" =~ ^v([0-9]+)\.([0-9]+)(\.([0-9]+))?$ ]] && \ [[ ! "$1" =~ ^v([0-9]+)\.([0-9]+)(\.([0-9]+))?$ ]] && \
err "arg1 accepts the following formats: v1.0 v1.0.0" err "arg1 accepts the following formats: v1.0 v1.0.0"
[[ -n "$(git tag | grep "^$1$")" ]] && \ git tag | grep -q "^$1$" &&
err "tag $1 already exists" err "tag $1 already exists"
last_tag=$(git tag | tail -1) last_tag=$(git tag | tail -1)
make -B -j$(nproc) VSN=$1 sha256sum.txt.asc make -B -j"$(nproc)" VSN="$1" sha256sum.txt.asc
{ {
echo undocker $1 echo undocker "$1"
echo echo
echo Changelog since $last_tag: echo Changelog since "$last_tag":
git log --pretty=format:"- [%cn] %s" $last_tag..HEAD git log --pretty=format:"- [%cn] %s" "$last_tag"..HEAD
echo echo
echo echo
echo sha256sums of released binaries: echo sha256sums of released binaries: