summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Harris <pharris@opentext.com>2015-01-26 16:35:44 -0500
committerPeter Harris <pharris@opentext.com>2015-01-26 16:35:44 -0500
commita0fbba4fe34fd467a03288d8945978406f5f1f2f (patch)
tree5b3119dc3b7acc458712f0df97a95afddab6df03
parent587b1a229bf351758ec93cc05406b1560251265c (diff)
Add xts-config replacement
This saves about half a second in run-time when running remotely (presumably due to all the extra round-trips of xset and xdpyinfo). The savings locally are less impressive (about 0.06s by saving a bunch of fork/exec pairs, and reducing the amount of output parsing going on).
-rw-r--r--config.go182
-rw-r--r--run.go14
2 files changed, 193 insertions, 3 deletions
diff --git a/config.go b/config.go
new file mode 100644
index 0000000..8e6cbca
--- /dev/null
+++ b/config.go
@@ -0,0 +1,182 @@
+package main
+
+import (
+ "bufio"
+ "fmt"
+ "os"
+ "path/filepath"
+ "regexp"
+ "strconv"
+ "strings"
+
+ "github.com/BurntSushi/xgb"
+ "github.com/BurntSushi/xgb/xproto"
+)
+
+func createConfig(outdir string) error {
+ c, err := xgb.NewConn()
+ if err != nil {
+ return err
+ }
+ defer c.Close()
+ gfpCookie := xproto.GetFontPath(c)
+
+ set := make(map[string]string)
+ s := xproto.Setup(c)
+
+ set["XT_PROTOCOL_VERSION"] = strconv.Itoa(int(s.ProtocolMajorVersion))
+ set["XT_PROTOCOL_REVISION"] = strconv.Itoa(int(s.ProtocolMinorVersion))
+ set["XT_SERVER_VENDOR"] = s.Vendor
+ set["XT_VENDOR_RELEASE"] = strconv.FormatUint(uint64(s.ReleaseNumber), 10)
+ set["XT_DISPLAYMOTIONBUFFERSIZE"] = strconv.FormatUint(uint64(s.MotionBufferSize), 10)
+ set["XT_SCREEN_COUNT"] = strconv.Itoa(len(s.Roots))
+ if c.DefaultScreen >= len(s.Roots) {
+ return fmt.Errorf("screen %d does not exist (only %d screens)", c.DefaultScreen, len(s.Roots))
+ }
+ set["XT_ALT_SCREEN"] = "UNSUPPORTED"
+ if len(s.Roots) > 1 {
+ if c.DefaultScreen == 0 {
+ set["XT_ALT_SCREEN"] = "1"
+ } else {
+ set["XT_ALT_SCREEN"] = "0"
+ }
+ }
+
+ r := s.Roots[c.DefaultScreen]
+ set["XT_WIDTH_MM"] = strconv.Itoa(int(r.WidthInMillimeters))
+ set["XT_HEIGHT_MM"] = strconv.Itoa(int(r.HeightInMillimeters))
+ set["XT_BLACK_PIXEL"] = strconv.FormatUint(uint64(r.BlackPixel), 10)
+ set["XT_WHITE_PIXEL"] = strconv.FormatUint(uint64(r.WhitePixel), 10)
+ set["XT_DOES_BACKING_STORE"] = strconv.Itoa(int(r.BackingStores))
+ set["XT_DOES_SAVE_UNDERS"] = "No"
+ if r.SaveUnders {
+ set["XT_DOES_SAVE_UNDERS"] = "Yes"
+ }
+ var list []string
+ visuals := make(map[string]struct{})
+ visType := map[byte]string{
+ xproto.VisualClassStaticGray: "StaticGray",
+ xproto.VisualClassGrayScale: "GrayScale",
+ xproto.VisualClassStaticColor: "StaticColor",
+ xproto.VisualClassPseudoColor: "PseudoColor",
+ xproto.VisualClassTrueColor: "TrueColor",
+ xproto.VisualClassDirectColor: "DirectColor",
+ }
+ for _, v := range r.AllowedDepths {
+ list = append(list, strconv.Itoa(int(v.Depth)))
+ for _, vis := range v.Visuals {
+ if class, ok := visType[vis.Class]; ok {
+ visuals[fmt.Sprintf("%s(%d)", class, v.Depth)] = struct{}{}
+ } else {
+ return fmt.Errorf("visual type %d invalid", vis.Class)
+ }
+ }
+ }
+ set["XT_PIXMAP_DEPTHS"] = strings.Join(list, " ")
+ list = list[:0]
+ for k, _ := range visuals {
+ list = append(list, k)
+ }
+ set["XT_VISUAL_CLASSES"] = strings.Join(list, " ")
+
+ // DISPLAY := os.Getenv("DISPLAY") or ":0"
+ tetRoot := env("TET_ROOT", "/usr/local/share")
+
+ gfp, err := gfpCookie.Reply()
+ if err != nil {
+ return err
+ }
+ list = list[:0]
+ for _, v := range gfp.Path {
+ list = append(list, v.Name)
+ }
+ fontPath := strings.Join(list, ",")
+ set["XT_FONTPATH_GOOD"] = fontPath
+ set["XT_FONTPATH"] = filepath.Join(tetRoot, "xts5", "fonts") + "," + fontPath
+
+ localDisplay := regexp.MustCompile(`^:\d+(\.\d+)?$`)
+ display := env("DISPLAY", ":0")
+ if localDisplay.MatchString(display) {
+ set["XT_LOCAL"] = "Yes"
+ set["XT_TCP"] = "No"
+ set["XT_DISPLAYHOST"] = ""
+ if hostname, err := os.Hostname(); err == nil {
+ // try connecting to the same display via TCP
+ tcpConn, err := xgb.NewConnDisplay(hostname + display)
+ if err == nil {
+ tcpConn.Close()
+ set["XT_TCP"] = "Yes"
+ set["XT_DISPLAYHOST"] = hostname
+ }
+ }
+ } else {
+ // Remote display
+ set["XT_TCP"] = "Yes"
+ hostname := ""
+ offset := strings.LastIndex(display, ":")
+ if offset >= 0 {
+ hostname = display[:offset]
+ }
+ set["XT_DISPLAYHOST"] = hostname
+
+ // Not a local display; admin is responsible for placing
+ // xtest fonts on the font path before running xts-config.
+ set["XT_FONTPATH"] = fontPath
+ list = list[:0]
+ for _, v := range gfp.Path {
+ // Remove xtest directory
+ if !strings.Contains(strings.ToLower(v.Name), "xtest") {
+ list = append(list, v.Name)
+ }
+ }
+ fpg := strings.Join(list, ",")
+ // If xtest directory is not called "xtest", remove the
+ // last directory in the path (as it's less likely to
+ // be the path containing "default"/"cursor" than the
+ // first directory in the path).
+ if fpg == fontPath && len(list) > 0 {
+ fpg = strings.Join(list[:len(list)-1], ",")
+ }
+ set["XT_FONTPATH_GOOD"] = fpg
+ }
+
+ config_in := filepath.Join(tetRoot, "xts5", "tetexec.cfg.in")
+
+ in, err := os.Open(config_in)
+ if err != nil {
+ return err
+ }
+ defer in.Close()
+ o, err := os.Create(*config)
+ if err != nil {
+ return err
+ }
+ defer o.Close()
+ out := bufio.NewWriter(o)
+ defer out.Flush()
+
+ scan := bufio.NewScanner(in)
+ for scan.Scan() {
+ text := scan.Text()
+ thing := strings.SplitN(text, "=", 2)
+ if len(thing) == 2 {
+ leftThing := strings.TrimSpace(thing[0])
+ if rep, ok := set[leftThing]; ok {
+ text = thing[0] + "=" + rep
+ delete(set, leftThing)
+ }
+ }
+ fmt.Fprintln(out, text)
+ }
+ if err := scan.Err(); err != nil {
+ return err
+ }
+ if len(set) == 0 {
+ return nil
+ }
+ fmt.Fprintln(out, "\n# Undocumented variables:\n\n")
+ for k, v := range set {
+ fmt.Fprintln(out, k+"="+v)
+ }
+ return nil
+}
diff --git a/run.go b/run.go
index 9a103fe..ddb03ad 100644
--- a/run.go
+++ b/run.go
@@ -8,6 +8,8 @@
// - Creates config file in results directory (instead of $TMPDIR)
//
// - Adds ability to run a single (or multiple) sub-test(s) (similar to run_assert)
+//
+// - Avoids shelling out to xts-config (and therefore xset/xdpyinfo) (faster remote startup)
package main
import (
@@ -23,6 +25,7 @@ import (
var config = flag.String("config", "", "Location of xts configuration file")
var output = flag.String("output", "xts-results", "Output directory to use")
var version = flag.Bool("version", false, "Display version number and exit")
+var extconfig = flag.Bool("extconfig", false, "Use external xts-config")
func env(evar string, def string) string {
rv := os.Getenv(evar)
@@ -32,8 +35,7 @@ func env(evar string, def string) string {
return rv
}
-func createConfig(outdir string) error {
- *config = filepath.Join(outdir, "tetexec.cfg")
+func createConfigExt(outdir string) error {
perl := env("PERL", "perl")
tetRoot := env("TET_ROOT", "/usr/local/share")
config_in := filepath.Join(tetRoot, "xts5", "tetexec.cfg.in")
@@ -104,7 +106,13 @@ func main() {
// Create the config file if necessary
if *config == "" {
- err := createConfig(outdir)
+ *config = filepath.Join(outdir, "tetexec.cfg")
+ var err error
+ if *extconfig {
+ err = createConfigExt(outdir)
+ } else {
+ err = createConfig(outdir)
+ }
if err != nil {
fmt.Fprintln(os.Stdout, err)
os.Exit(1)