diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index fdc32c4a7..390b1ec66 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -79,6 +79,21 @@ jobs: env: SUPABASE_INTERNAL_IMAGE_REGISTRY: ghcr.io + link: + name: Link + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v6 + - uses: actions/setup-go@v6 + with: + go-version-file: go.mod + cache: true + - run: go build main.go + - run: ./main link + env: + SUPABASE_ACCESS_TOKEN: ${{ secrets.SUPABASE_ACCESS_TOKEN }} + SUPABASE_PROJECT_ID: ${{ secrets.SUPABASE_PROJECT_ID }} + codegen: name: Codegen runs-on: ubuntu-latest diff --git a/fsevents/fsevents.go b/fsevents/fsevents.go new file mode 100644 index 000000000..d75d31932 --- /dev/null +++ b/fsevents/fsevents.go @@ -0,0 +1,117 @@ +//go:build darwin + +// Package fsevents provides file system notifications on macOS. +package fsevents + +import ( + "syscall" + "time" +) + +// Event represents a single file system notification. +type Event struct { + // Path holds the path to the item that's changed, relative + // to its device's root. + // Use DeviceForPath to determine the absolute path that's + // being referred to. + Path string + + // Flags holds details what has happened. + Flags EventFlags + + // ID holds the event ID. + // + // Each event ID comes from the most recent event being reported + // in the corresponding directory named in the EventStream.Paths field + // Event IDs all come from a single global source. + // They are guaranteed to always be increasing, usually in leaps + // and bounds, even across system reboots and moving drives from + // one machine to another. If you were to + // stop processing events from this stream after this event + // and resume processing them later from a newly-created + // EventStream, this is the value you would pass for the + // EventStream.EventID along with Resume=true. + ID uint64 +} + +// DeviceForPath returns the device ID for the specified volume. +func DeviceForPath(path string) (int32, error) { + stat := syscall.Stat_t{} + if err := syscall.Lstat(path, &stat); err != nil { + return 0, err + } + return stat.Dev, nil +} + +// EventStream is the primary interface to FSEvents +// You can provide your own event channel if you wish (or one will be +// created on Start). +// +// es := &EventStream{Paths: []string{"/tmp"}, Flags: 0} +// es.Start() +// es.Stop() +// ... +type EventStream struct { + // Events holds the channel on which events will be sent. + // It's initialized by EventStream.Start if nil. + Events chan []Event + + // Paths holds the set of paths to watch, each + // specifying the root of a filesystem hierarchy to be + // watched for modifications. + Paths []string + + // Flags specifies what events to receive on the stream. + Flags CreateFlags + + // Resume specifies that watching should resume from the event + // specified by EventID. + Resume bool + + // EventID holds the most recent event ID. + // + // NOTE: this is updated asynchronously by the + // watcher and should not be accessed while + // the stream has been started. + EventID uint64 + + // Latency holds the number of seconds the service should wait after hearing + // about an event from the kernel before passing it along to the + // client via its callback. Specifying a larger value may result + // in more effective temporal coalescing, resulting in fewer + // callbacks and greater overall efficiency. + Latency time.Duration + + // When Device is non-zero, the watcher will watch events on the + // device with this ID, and the paths in the Paths field are + // interpreted relative to the device's root. + // + // The device ID is the same as the st_dev field from a stat + // structure of a file on that device or the f_fsid[0] field of + // a statfs structure. + Device int32 +} + +// Start listening to an event stream. This creates es.Events if it's not already +// a valid channel. +func (es *EventStream) Start() error { + return nil +} + +// Flush flushes events that have occurred but haven't been delivered. +// If sync is true, it will block until all the events have been delivered, +// otherwise it will return immediately. +func (es *EventStream) Flush(sync bool) { +} + +// Stop stops listening to the event stream. +func (es *EventStream) Stop() { +} + +// Restart restarts the event listener. This +// can be used to change the current watch flags. +func (es *EventStream) Restart() error { + es.Stop() + es.Resume = true + return es.Start() +} diff --git a/fsevents/go.mod b/fsevents/go.mod new file mode 100644 index 000000000..41e670c56 --- /dev/null +++ b/fsevents/go.mod @@ -0,0 +1,3 @@ +go 1.24.10 + +module github.com/fsnotify/fsevents diff --git a/fsevents/wrap.go b/fsevents/wrap.go new file mode 100644 index 000000000..f12125b7e --- /dev/null +++ b/fsevents/wrap.go @@ -0,0 +1,40 @@ +//go:build darwin + +package fsevents + +// CreateFlags specifies what events will be seen in an event stream. +type CreateFlags uint32 + +const ( + // IgnoreSelf doesn't send events triggered by the current process (macOS 10.6+). + // + // Don't send events that were triggered by the current process. + // This is useful for reducing the volume of events that are + // sent. It is only useful if your process might modify the file + // system hierarchy beneath the path(s) being monitored. Note: + // this has no effect on historical events, i.e., those + // delivered before the HistoryDone sentinel event. + IgnoreSelf = CreateFlags(0) + + // FileEvents sends events about individual files, generating significantly + // more events (macOS 10.7+) than directory level notifications. + FileEvents = CreateFlags(1) +) + +// EventFlags passed to the FSEventStreamCallback function. +// These correspond directly to the flags as described here: +// https://developer.apple.com/documentation/coreservices/1455361-fseventstreameventflags +type EventFlags uint32 + +const ( + // ItemCreated indicates that a file or directory has been created. + ItemCreated = EventFlags(0) + + // ItemIsDir indicates that the item is a directory. + ItemIsDir = EventFlags(1) +) + +// LatestEventID returns the most recently generated event ID, system-wide. +func LatestEventID() uint64 { + return 0 +} diff --git a/go.mod b/go.mod index 63471b955..5ce13247d 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/supabase/cli -go 1.24.9 +go 1.24.10 require ( github.com/BurntSushi/toml v1.5.0 @@ -455,6 +455,8 @@ require ( replace github.com/supabase/cli/pkg v1.0.0 => ./pkg +replace github.com/fsnotify/fsevents v0.2.0 => ./fsevents + tool ( github.com/golangci/golangci-lint/v2/cmd/golangci-lint github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen diff --git a/go.sum b/go.sum index 23e2db853..c18199eef 100644 --- a/go.sum +++ b/go.sum @@ -327,8 +327,6 @@ github.com/firefart/nonamedreturns v1.0.6 h1:vmiBcKV/3EqKY3ZiPxCINmpS431OcE1S47A github.com/firefart/nonamedreturns v1.0.6/go.mod h1:R8NisJnSIpvPWheCq0mNRXJok6D8h7fagJTF8EMEwCo= github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= -github.com/fsnotify/fsevents v0.2.0 h1:BRlvlqjvNTfogHfeBOFvSC9N0Ddy+wzQCQukyoD7o/c= -github.com/fsnotify/fsevents v0.2.0/go.mod h1:B3eEk39i4hz8y1zaWS/wPrAP4O6wkIl7HQwKBr1qH/w= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k= diff --git a/pkg/go.mod b/pkg/go.mod index 1d4cb6c85..2dfb67c77 100644 --- a/pkg/go.mod +++ b/pkg/go.mod @@ -1,6 +1,6 @@ module github.com/supabase/cli/pkg -go 1.24.4 +go 1.24.10 require ( github.com/BurntSushi/toml v1.5.0