1
1
package sc
2
2
3
3
import (
4
+ "errors"
4
5
"fmt"
6
+ "os"
5
7
"os/exec"
6
8
"strconv"
9
+ "strings"
7
10
"time"
8
11
)
9
12
10
13
// DefaultServerPort is the default listening port for scsynth.
11
14
const DefaultServerPort = 57120
12
15
16
+ // ErrNoScsynth happens when you try to start a SuperCollider
17
+ // server but do not have an scsynth executable in your PATH.
18
+ var ErrNoScsynth = errors .New ("Please install scsynth somewhere in your PATH." )
19
+
13
20
// Server represents a running instance of scsynth.
14
21
type Server struct {
15
22
* exec.Cmd
@@ -19,6 +26,46 @@ type Server struct {
19
26
StartTimeout time.Duration
20
27
}
21
28
29
+ // getServerPath gets the path to the scsynth executable.
30
+ func (s * Server ) getServerPath () (string , error ) {
31
+ for _ , file := range strings .Split (ServerPath , ":" ) {
32
+ ok , err := isExecutable (file )
33
+ if err != nil {
34
+ return "" , err
35
+ }
36
+ if ok {
37
+ return file , nil
38
+ }
39
+ }
40
+
41
+ path , hasPath := os .LookupEnv ("PATH" )
42
+ if ! hasPath {
43
+ return "" , ErrNoScsynth
44
+ }
45
+
46
+ for _ , file := range strings .Split (path , ":" ) {
47
+ ok , err := isExecutable (file )
48
+ if err != nil {
49
+ return "" , err
50
+ }
51
+ if ok {
52
+ return file , nil
53
+ }
54
+ }
55
+ return "" , ErrNoScsynth
56
+ }
57
+
58
+ // isExecutable returns true if the provided file is executable, false otherwise.
59
+ // It also returns any error that occurs while trying to read the file.
60
+ func isExecutable (filename string ) (bool , error ) {
61
+ info , err := os .Stat (filename )
62
+ if err != nil {
63
+ return false , err
64
+ }
65
+ mode := info .Mode ()
66
+ return ((mode & 0x01 ) | (mode & 0x08 ) | (mode & 0x40 )) != 0 , nil
67
+ }
68
+
22
69
// args gets the command line args to scsynth
23
70
func (s * Server ) args () ([]string , error ) {
24
71
// Get the port.
@@ -48,7 +95,13 @@ func (s *Server) Start() error {
48
95
if err != nil {
49
96
return err
50
97
}
51
- s .Cmd = exec .Command (ServerPath , args ... )
98
+
99
+ serverPath , err := s .getServerPath ()
100
+ if err != nil {
101
+ return err
102
+ }
103
+
104
+ s .Cmd = exec .Command (serverPath , args ... )
52
105
if err := s .Cmd .Start (); err != nil {
53
106
return err
54
107
}
0 commit comments