Skip to content

Commit

Permalink
WIP: support building from Windows
Browse files Browse the repository at this point in the history
Signed-off-by: Jason Hall <jason@chainguard.dev>
  • Loading branch information
imjasonh committed Feb 24, 2023
1 parent 89912f3 commit 91436ca
Show file tree
Hide file tree
Showing 14 changed files with 321 additions and 109 deletions.
11 changes: 7 additions & 4 deletions .github/workflows/build-samples.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ name: Build Images
on:
pull_request:
push:
workflow_dispatch:

jobs:
build-nginx-on-all-arches:
Expand Down Expand Up @@ -32,23 +33,25 @@ jobs:
build-all-examples-one-arch:
name: build-all-examples-amd64
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
platform: [ubuntu-latest, macos-latest, windows-latest]
runs-on: ${{ matrix.platform }}

steps:
- uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v2.4.0
- uses: actions/setup-go@6edd4406fa81c3da01a34fa6f6343087c207a568 # v2.1.5
with:
go-version: 1.19
check-latest: true
- name: Setup QEMU
uses: docker/setup-qemu-action@v2.1.0

- name: build
run: |
make apko
./apko version
- name: build images
shell: bash
run: |
for cfg in $(find ./examples/ -name '*.yaml'); do
name=$(basename ${cfg} .yaml)
Expand Down
34 changes: 2 additions & 32 deletions pkg/apk/impl/fs/memfs.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ package fs
import (
"archive/tar"
"bytes"
"encoding/binary"
"errors"
"fmt"
"io"
Expand All @@ -28,7 +27,6 @@ import (

"github.com/blang/vfs"
origMemfs "github.com/blang/vfs/memfs"
"golang.org/x/sys/unix"
)

const (
Expand Down Expand Up @@ -169,39 +167,11 @@ func (m *memFS) open(name string) (*memFile, error) {
}

func (m *memFS) Mknod(path string, mode uint32, dev int) error {
file, err := m.OpenFile(
path,
os.O_CREATE|os.O_WRONLY|os.O_TRUNC,
fs.FileMode(mode)|os.ModeCharDevice|os.ModeDevice,
)
if err != nil {
return err
}
defer file.Close()
// save the major and minor numbers in the file itself
devNumbers := []uint32{unix.Major(uint64(dev)), unix.Minor(uint64(dev))}
return binary.Write(file, binary.LittleEndian, devNumbers)
return m.mknod(path, mode, dev)
}

func (m *memFS) Readnod(name string) (dev int, err error) {
file, err := m.Open(name)
if err != nil {
return 0, err
}
defer file.Close()
fi, err := file.Stat()
if err != nil {
return 0, err
}
if fi.Mode()&os.ModeCharDevice != os.ModeCharDevice {
return 0, fmt.Errorf("%s not a character device", name)
}
// read the major and minor numbers from the file itself
devNumbers := make([]uint32, 2)
if err := binary.Read(file, binary.LittleEndian, devNumbers); err != nil {
return 0, err
}
return int(unix.Mkdev(devNumbers[0], devNumbers[1])), nil
return m.readnod(name)
}

func (m *memFS) Chmod(path string, perm fs.FileMode) error {
Expand Down
26 changes: 26 additions & 0 deletions pkg/apk/impl/fs/rwofs_windows.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// Copyright 2022, 2023 Chainguard, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//go:build windows
// +build windows

package fs

import "io/fs"

func (f *dirFS) modeCharDevice(string, fs.FileInfo, fs.FileMode) error { return nil }
func (f *dirFS) mknod(string, string, uint32, int) error { return nil }

func (m *memFS) mknod(string, uint32, int) error { return nil }
func (m *memFS) readnod(string) (int, error) { return 0, nil }
26 changes: 2 additions & 24 deletions pkg/apk/impl/fs/rwosfs.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,7 @@ import (
"path/filepath"
"strings"
"sync"
"syscall"
"time"

"golang.org/x/sys/unix"
)

type dirFSOpts struct {
Expand Down Expand Up @@ -142,19 +139,7 @@ func DirFS(dir string, opts ...DirFSOption) FullFS {
err = f.overrides.Symlink(target, path)
}
case fs.ModeCharDevice:
var dev int
sys := fi.Sys()
st1, ok1 := sys.(*syscall.Stat_t)
st2, ok2 := sys.(*unix.Stat_t)
switch {
case ok1:
dev = int(st1.Rdev)
case ok2:
dev = int(st2.Rdev)
default:
return fmt.Errorf("unsupported type %T", sys)
}
err = f.overrides.Mknod(path, uint32(unix.S_IFCHR|mode), dev)
return f.modeCharDevice(path, fi, mode)
default:
var memFile File
memFile, err = f.overrides.OpenFile(path, os.O_CREATE, perm)
Expand Down Expand Up @@ -492,14 +477,7 @@ func (f *dirFS) Chown(path string, uid int, gid int) error {
}

func (f *dirFS) Mknod(name string, mode uint32, dev int) error {
if f.caseSensitiveOnDisk(name) {
err := unix.Mknod(filepath.Join(f.base, name), mode, dev)
// what if we could not create it? Just create a regular file there, and memory will override
if err != nil {
_ = os.WriteFile(filepath.Join(f.base, name), nil, 0)
}
}
return f.overrides.Mknod(name, mode, dev)
return f.mknod(f.base, name, mode, dev)
}

// sanitize ensures that we never go beyond the root of the filesystem
Expand Down
92 changes: 92 additions & 0 deletions pkg/apk/impl/fs/rwosfs_unix.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
// Copyright 2022, 2023 Chainguard, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//go:build unix
// +build unix

package fs

import (
"encoding/binary"
"fmt"
"io/fs"
"os"
"path/filepath"
"syscall"

"golang.org/x/sys/unix"
)

func (f *dirFS) modeCharDevice(path string, fi fs.FileInfo, mode fs.FileMode) error {
var dev int
sys := fi.Sys()
st1, ok1 := sys.(*syscall.Stat_t)
st2, ok2 := sys.(*unix.Stat_t)
switch {
case ok1:
dev = int(st1.Rdev)
case ok2:
dev = int(st2.Rdev)
default:
return fmt.Errorf("unsupported type %T", sys)
}
return f.overrides.Mknod(path, uint32(unix.S_IFCHR|mode), dev)
}

func (f *dirFS) mknod(base, name string, mode uint32, dev int) error {
if f.caseSensitiveOnDisk(name) {
err := unix.Mknod(filepath.Join(f.base, name), mode, dev)
// what if we could not create it? Just create a regular file there, and memory will override
if err != nil {
_ = os.WriteFile(filepath.Join(f.base, name), nil, 0)
}
}
return f.overrides.Mknod(name, mode, dev)
}

func (m *memFS) mknod(path string, mode uint32, dev int) error {
file, err := m.OpenFile(
path,
os.O_CREATE|os.O_WRONLY|os.O_TRUNC,
fs.FileMode(mode)|os.ModeCharDevice|os.ModeDevice,
)
if err != nil {
return err
}
defer file.Close()
// save the major and minor numbers in the file itself
devNumbers := []uint32{unix.Major(uint64(dev)), unix.Minor(uint64(dev))}
return binary.Write(file, binary.LittleEndian, devNumbers)
}

func (m *memFS) readnod(name string) (dev int, err error) {
file, err := m.Open(name)
if err != nil {
return 0, err
}
defer file.Close()
fi, err := file.Stat()
if err != nil {
return 0, err
}
if fi.Mode()&os.ModeCharDevice != os.ModeCharDevice {
return 0, fmt.Errorf("%s not a character device", name)
}
// read the major and minor numbers from the file itself
devNumbers := make([]uint32, 2)
if err := binary.Read(file, binary.LittleEndian, devNumbers); err != nil {
return 0, err
}
return int(unix.Mkdev(devNumbers[0], devNumbers[1])), nil
}
4 changes: 1 addition & 3 deletions pkg/apk/impl/implementation.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ import (
"gitlab.alpinelinux.org/alpine/go/pkg/repository"
"go.lsp.dev/uri"
"golang.org/x/sync/errgroup"
"golang.org/x/sys/unix"

apkfs "chainguard.dev/apko/pkg/apk/impl/fs"
)
Expand Down Expand Up @@ -234,8 +233,7 @@ func (a *APKImplementation) InitDB(versions ...string) error {
}
}
for _, e := range initDeviceFiles {
perms := uint32(e.perms.Perm())
err := a.fs.Mknod(e.path, unix.S_IFCHR|perms, int(unix.Mkdev(e.major, e.minor)))
err := a.initDeviceFile(e)
if !a.ignoreMknodErrors && err != nil {
return fmt.Errorf("failed to create char device %s: %w", e.path, err)
}
Expand Down
25 changes: 25 additions & 0 deletions pkg/apk/impl/implementation_unix.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// Copyright 2023 Chainguard, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//go:build unix
// +build unix

package impl

import "golang.org/x/sys/unix"

func (a *APKImplementation) initDeviceFile(e deviceFile) error {
perms := uint32(e.perms.Perm())
return a.fs.Mknod(e.path, unix.S_IFCHR|perms, int(unix.Mkdev(e.major, e.minor)))
}
20 changes: 20 additions & 0 deletions pkg/apk/impl/implementation_windows.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// Copyright 2023 Chainguard, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//go:build windows
// +build windows

package impl

func (a *APKImplementation) initDeviceFile(e deviceFile) error { return nil }
2 changes: 1 addition & 1 deletion pkg/apk/impl/installed.go
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ func (a *APKImplementation) updateScriptsTar(pkg *repository.Package, controlTar
}
// only need to rewind if the file has tar in it
if fi.Size() >= 1024 {
if _, err = scripts.Seek(-1024, os.SEEK_END); err != nil {
if _, err = scripts.Seek(-1024, io.SeekEnd); err != nil {
return fmt.Errorf("could not seek to end of tar file: %w", err)
}
}
Expand Down
17 changes: 17 additions & 0 deletions pkg/build/chardevices.go → pkg/build/chardevices_unix.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,20 @@
// Copyright 2022, 2023 Chainguard, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//go:build unix
// +build unix

package build

import (
Expand Down
22 changes: 22 additions & 0 deletions pkg/build/chardevices_windows.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// Copyright 2022, 2023 Chainguard, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//go:build windows
// +build windows

package build

import apkfs "chainguard.dev/apko/pkg/apk/impl/fs"

func (*defaultBuildImplementation) InstallCharDevices(apkfs.FullFS) error { return nil }
Loading

0 comments on commit 91436ca

Please sign in to comment.