@ -43,6 +43,8 @@ type Build struct {
Tmp string
Tmp string
// Go is the path to the Go binary to use for building.
// Go is the path to the Go binary to use for building.
Go string
Go string
// Yarn is the path to the yarn binary to use for building the web client assets.
Yarn string
// Version is the version info of the build.
// Version is the version info of the build.
Version mkversion . VersionInfo
Version mkversion . VersionInfo
// Time is the timestamp of the build.
// Time is the timestamp of the build.
@ -79,15 +81,20 @@ func NewBuild(repo, out string) (*Build, error) {
if err != nil {
if err != nil {
return nil , fmt . Errorf ( "finding module root: %w" , err )
return nil , fmt . Errorf ( "finding module root: %w" , err )
}
}
goTool , err := find Go( repo )
goTool , err := find Tool( repo , "go" )
if err != nil {
if err != nil {
return nil , fmt . Errorf ( "finding go binary: %w" , err )
return nil , fmt . Errorf ( "finding go binary: %w" , err )
}
}
yarnTool , err := findTool ( repo , "yarn" )
if err != nil {
return nil , fmt . Errorf ( "finding yarn binary: %w" , err )
}
b := & Build {
b := & Build {
Repo : repo ,
Repo : repo ,
Tmp : tmp ,
Tmp : tmp ,
Out : out ,
Out : out ,
Go : goTool ,
Go : goTool ,
Yarn : yarnTool ,
Version : mkversion . Info ( ) ,
Version : mkversion . Info ( ) ,
Time : time . Now ( ) . UTC ( ) ,
Time : time . Now ( ) . UTC ( ) ,
extra : map [ any ] any { } ,
extra : map [ any ] any { } ,
@ -180,6 +187,24 @@ func (b *Build) TmpDir() string {
return ret
return ret
}
}
// BuildWebClientAssets builds the JS and CSS assets used by the web client.
// Assets are built in the client/web/build directory and embedded in
// the cmd/tailscale binary.
func ( b * Build ) BuildWebClientAssets ( ) error {
// Nothing in the web client assets is platform-specific,
// so we only need to build it once.
return b . Once ( "build-web-client-assets" , func ( ) error {
dir := filepath . Join ( b . Repo , "client" , "web" )
if err := b . Command ( dir , b . Yarn , "install" ) . Run ( ) ; err != nil {
return err
}
if err := b . Command ( dir , b . Yarn , "build" ) . Run ( ) ; err != nil {
return err
}
return nil
} )
}
// BuildGoBinary builds the Go binary at path and returns the path to the
// BuildGoBinary builds the Go binary at path and returns the path to the
// binary. Builds are cached by path and env, so each build only happens once
// binary. Builds are cached by path and env, so each build only happens once
// per process execution.
// per process execution.
@ -303,16 +328,19 @@ func findModRoot(path string) (string, error) {
}
}
}
}
func findGo ( path string ) ( string , error ) {
// findTool returns the path to the specified named tool.
toolGo := filepath . Join ( path , "tool/go" )
// It first looks in the "tool" directory in the provided path,
if _ , err := os . Stat ( toolGo ) ; err == nil {
// then in the $PATH environment variable.
return toolGo , nil
func findTool ( path , name string ) ( string , error ) {
tool := filepath . Join ( path , "tool" , name )
if _ , err := os . Stat ( tool ) ; err == nil {
return tool , nil
}
}
toolGo , err := exec . LookPath ( "go" )
tool , err := exec . LookPath ( name )
if err != nil {
if err != nil {
return "" , err
return "" , err
}
}
return tool Go , nil
return tool , nil
}
}
// FilterTargets returns the subset of targets that match any of the filters.
// FilterTargets returns the subset of targets that match any of the filters.