Skip to content

Commit

Permalink
make setting the process group ID optional
Browse files Browse the repository at this point in the history
  • Loading branch information
dmiller-figma committed Jan 6, 2025
1 parent ffa6c14 commit b8db03a
Show file tree
Hide file tree
Showing 12 changed files with 49 additions and 32 deletions.
4 changes: 3 additions & 1 deletion cmd/ibazel/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ var overrideableBazelFlags []string = []string{

var debounceDuration = flag.Duration("debounce", 100*time.Millisecond, "Debounce duration")
var logToFile = flag.String("log_to_file", "-", "Log iBazel stderr to a file instead of os.Stderr")
var setPGID = flag.Bool("set_pgid", true, "Whether to set the process group ID")

func usage() {
fmt.Fprintf(os.Stderr, `iBazel - Version %s
Expand Down Expand Up @@ -192,6 +193,7 @@ func main() {
log.Fatalf("Error creating iBazel: %s", err)
}
i.SetDebounceDuration(*debounceDuration)
i.SetSetPGID(*setPGID)
defer i.Cleanup()

// increase the number of files that this process can
Expand All @@ -210,7 +212,7 @@ func applyDefaultBazelArgs(bazelArgs []string) []string {
return bazelArgs
}
}
if (isTerminal()) {
if isTerminal() {
return append(bazelArgs, "--isatty=1")
} else {
return append(bazelArgs, "--isatty=0")
Expand Down
7 changes: 3 additions & 4 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,8 @@ require (
gopkg.in/fsnotify.v1 v1.4.7 // indirect
)

require (
golang.org/x/sys v0.0.0-20220908164124-27713097b956 // indirect
google.golang.org/protobuf v1.28.0 // indirect
)
require golang.org/x/sys v0.0.0-20220908164124-27713097b956

require google.golang.org/protobuf v1.28.0 // indirect

go 1.19
5 changes: 5 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ github.com/fsnotify/fsnotify v1.5.4 h1:jRbGcIw6P2Meqdwuo0H1p6JVLbL5DHKAKlYndzMwV
github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU=
github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=
github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw=
github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
Expand Down Expand Up @@ -58,6 +59,7 @@ github.com/smartystreets/goconvey v1.7.2 h1:9RBaZCeXEQ3UselpuwUQHltGVXvdwm6cv1hg
github.com/smartystreets/goconvey v1.7.2/go.mod h1:Vw0tHAZW6lzCRk3xgdin6fKYcG+G3Pg9vgXWeJpQFMM=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c h1:F1jZWGFhYfh0Ci55sIpILtKKK8p3i2/krTr0H1rg74I=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
Expand All @@ -66,9 +68,12 @@ golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20220908164124-27713097b956 h1:XeJjHH1KiLpKGb6lvMiksZ9l0fVUh+AmGcm0nOMEBOY=
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
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/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
google.golang.org/grpc v1.50.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
Expand Down
4 changes: 2 additions & 2 deletions internal/ibazel/command/command.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ type Command interface {

// start will be called by most implementations since this logic is extremely
// common.
func start(b bazel.Bazel, target string, args []string) (*bytes.Buffer, process_group.ProcessGroup) {
func start(b bazel.Bazel, target string, setPGID bool, args []string) (*bytes.Buffer, process_group.ProcessGroup) {
var filePattern strings.Builder
filePattern.WriteString("bazel_script_path*")
if runtime.GOOS == "windows" {
Expand All @@ -75,7 +75,7 @@ func start(b bazel.Bazel, target string, args []string) (*bytes.Buffer, process_

// Now that we have built the target, construct a executable form of it for
// execution in a go routine.
cmd := execCommand(runScriptPath, args...)
cmd := execCommand(runScriptPath, setPGID, args...)
cmd.RootProcess().Stdout = os.Stdout
cmd.RootProcess().Stderr = os.Stderr

Expand Down
4 changes: 2 additions & 2 deletions internal/ibazel/command/command_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,8 @@ func assertKilled(t *testing.T, cmd *exec.Cmd) {
func TestSubprocessRunning(t *testing.T) {
log.SetLogger(t)

execCommand = func(name string, args ...string) process_group.ProcessGroup {
return oldExecCommand("ls") // Every system has ls.
execCommand = func(name string, setPGID bool, args ...string) process_group.ProcessGroup {
return oldExecCommand("ls", setPGID) // Every system has ls.
}
defer func() { execCommand = oldExecCommand }()

Expand Down
6 changes: 4 additions & 2 deletions internal/ibazel/command/default_command.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,17 +30,19 @@ type defaultCommand struct {
args []string
pg process_group.ProcessGroup
termSync sync.Once
setPGID bool
}

// DefaultCommand is the normal mode of interacting with iBazel. If you start a
// server in this mode and notify of changes the server will be killed and
// restarted.
func DefaultCommand(startupArgs []string, bazelArgs []string, target string, args []string) Command {
func DefaultCommand(startupArgs []string, bazelArgs []string, target string, setPGID bool, args []string) Command {
return &defaultCommand{
target: target,
startupArgs: startupArgs,
bazelArgs: bazelArgs,
args: args,
setPGID: setPGID,
}
}

Expand Down Expand Up @@ -70,7 +72,7 @@ func (c *defaultCommand) Start() (*bytes.Buffer, error) {
b.WriteToStdout(true)

var outputBuffer *bytes.Buffer
outputBuffer, c.pg = start(b, c.target, c.args)
outputBuffer, c.pg = start(b, c.target, c.setPGID, c.args)

c.pg.RootProcess().Env = os.Environ()

Expand Down
18 changes: 9 additions & 9 deletions internal/ibazel/command/default_command_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,17 +31,17 @@ func TestDefaultCommand(t *testing.T) {

if runtime.GOOS == "windows" {
// TODO(jchw): Remove hardcoded path.
toKill = process_group.Command("C:\\windows\\system32\\notepad")
toKill = process_group.Command("C:\\windows\\system32\\notepad", true)
} else {
toKill = process_group.Command("sleep", "10s")
toKill = process_group.Command("sleep", true, "10s")
}

execCommand = func(name string, args ...string) process_group.ProcessGroup {
execCommand = func(name string, setPGID bool, args ...string) process_group.ProcessGroup {
if runtime.GOOS == "windows" {
// TODO(jchw): Remove hardcoded path.
return oldExecCommand("C:\\windows\\system32\\where")
return oldExecCommand("C:\\windows\\system32\\where", setPGID, args...)
}
return oldExecCommand("ls") // Every system has ls.
return oldExecCommand("ls", setPGID) // Every system has ls.
}
defer func() { execCommand = oldExecCommand }()

Expand Down Expand Up @@ -71,18 +71,18 @@ func TestDefaultCommand_Start(t *testing.T) {
log.SetLogger(t)

// Set up mock execCommand and prep it to be returned
execCommand = func(name string, args ...string) process_group.ProcessGroup {
execCommand = func(name string, setPGID bool, args ...string) process_group.ProcessGroup {
if runtime.GOOS == "windows" {
// TODO(jchw): Remove hardcoded path.
return oldExecCommand("C:\\windows\\system32\\where")
return oldExecCommand("C:\\windows\\system32\\where", setPGID, args...)
}
return oldExecCommand("ls") // Every system has ls.
return oldExecCommand("ls", setPGID, args...) // Every system has ls.
}
defer func() { execCommand = oldExecCommand }()

b := &mock_bazel.MockBazel{}

_, pg := start(b, "//path/to:target", []string{"moo"})
_, pg := start(b, "//path/to:target", true, []string{"moo"})
pg.Start()

if pg.RootProcess().Stdout != os.Stdout {
Expand Down
7 changes: 5 additions & 2 deletions internal/ibazel/command/notify_command.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,16 +32,18 @@ type notifyCommand struct {
pg process_group.ProcessGroup
stdin io.WriteCloser
termSync sync.Once
setPGID bool
}

// NotifyCommand is an alternate mode for starting a command. In this mode the
// command will be notified on stdin that the source files have changed.
func NotifyCommand(startupArgs []string, bazelArgs []string, target string, args []string) Command {
func NotifyCommand(startupArgs []string, bazelArgs []string, target string, setPGID bool, args []string) Command {
return &notifyCommand{
startupArgs: startupArgs,
target: target,
bazelArgs: bazelArgs,
args: args,
setPGID: setPGID,
}
}

Expand Down Expand Up @@ -71,7 +73,7 @@ func (c *notifyCommand) Start() (*bytes.Buffer, error) {
b.WriteToStdout(true)

var outputBuffer *bytes.Buffer
outputBuffer, c.pg = start(b, c.target, c.args)
outputBuffer, c.pg = start(b, c.target, c.setPGID, c.args)
// Keep the writer around.
var err error
c.stdin, err = c.pg.RootProcess().StdinPipe()
Expand Down Expand Up @@ -126,6 +128,7 @@ func (c *notifyCommand) NotifyOfChanges() *bytes.Buffer {
if !c.IsSubprocessRunning() {
log.Log("Restarting process...")
c.Terminate()
// TODO(dmiller): Report the error to the user.
c.Start()
}
}
Expand Down
8 changes: 4 additions & 4 deletions internal/ibazel/command/notify_command_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ import (
func TestNotifyCommand(t *testing.T) {
log.SetLogger(t)

pg := process_group.Command("cat")
pg := process_group.Command("cat", true)

c := &notifyCommand{
args: []string{"moo"},
Expand Down Expand Up @@ -92,9 +92,9 @@ func TestNotifyCommand_Restart(t *testing.T) {

var pg process_group.ProcessGroup

pg = process_group.Command("ls")
execCommand = func(name string, args ...string) process_group.ProcessGroup {
return oldExecCommand("ls")
pg = process_group.Command("ls", true)
execCommand = func(name string, setPGID bool, args ...string) process_group.ProcessGroup {
return oldExecCommand("ls", setPGID, args...)
}
defer func() { execCommand = oldExecCommand }()

Expand Down
9 changes: 7 additions & 2 deletions internal/ibazel/ibazel.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ type IBazel struct {
args []string
bazelArgs []string
startupArgs []string
setPGID bool

sigs chan os.Signal // Signals channel for the current process
interruptCount int
Expand Down Expand Up @@ -185,6 +186,10 @@ func (i *IBazel) SetDebounceDuration(debounceDuration time.Duration) {
i.debounceDuration = debounceDuration
}

func (i *IBazel) SetSetPGID(setPGID bool) {
i.setPGID = setPGID
}

func (i *IBazel) Cleanup() {
i.buildFileWatcher.Close()
i.sourceFileWatcher.Close()
Expand Down Expand Up @@ -423,9 +428,9 @@ func (i *IBazel) setupRun(target string) command.Command {

if commandNotify {
log.Logf("Launching with notifications")
return commandNotifyCommand(i.startupArgs, i.bazelArgs, target, i.args)
return commandNotifyCommand(i.startupArgs, i.bazelArgs, target, i.setPGID, i.args)
} else {
return commandDefaultCommand(i.startupArgs, i.bazelArgs, target, i.args)
return commandDefaultCommand(i.startupArgs, i.bazelArgs, target, i.setPGID, i.args)
}
}

Expand Down
4 changes: 2 additions & 2 deletions internal/ibazel/ibazel_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ func getMockCommand(i *IBazel) *mockCommand {
}

func init() {
commandDefaultCommand = func(startupArgs []string, bazelArgs []string, target string, args []string) command.Command {
commandDefaultCommand = func(startupArgs []string, bazelArgs []string, target string, setPGID bool, args []string) command.Command {
// Don't do anything
return &mockCommand{
startupArgs: startupArgs,
Expand Down Expand Up @@ -347,7 +347,7 @@ func TestIBazelTest(t *testing.T) {
func TestIBazelRun_notifyPreexistiingJobWhenStarting(t *testing.T) {
log.SetTesting(t)

commandDefaultCommand = func(startupArgs []string, bazelArgs []string, target string, args []string) command.Command {
commandDefaultCommand = func(startupArgs []string, bazelArgs []string, target string, setPGID bool, args []string) command.Command {
assertEqual(t, startupArgs, []string{}, "Startup args")
assertEqual(t, bazelArgs, []string{}, "Bazel args")
assertEqual(t, target, "", "Target")
Expand Down
5 changes: 3 additions & 2 deletions internal/ibazel/process_group/process_group_unix.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.

//go:build !windows
// +build !windows

package process_group
Expand All @@ -27,9 +28,9 @@ type unixProcessGroup struct {

// Command creates a new ProcessGroup with a root command specified by the
// arguments.
func Command(name string, arg ...string) ProcessGroup {
func Command(name string, setPGID bool, arg ...string) ProcessGroup {
root := exec.Command(name, arg...)
root.SysProcAttr = &syscall.SysProcAttr{Setpgid: true}
root.SysProcAttr = &syscall.SysProcAttr{Setpgid: setPGID}
return &unixProcessGroup{root}
}

Expand Down

0 comments on commit b8db03a

Please sign in to comment.