diff options
author | 2018-06-27 17:30:37 +0200 | |
---|---|---|
committer | 2018-06-27 17:30:37 +0200 | |
commit | 63dc51c35d26c837295ac0ef33c1b8e41353ea35 (patch) | |
tree | 24918fe062c14b29f1c69b2e024cb8d66d045c50 | |
parent | d9bb450ee8898cb810027897a32afd3adcb05d9f (diff) |
Merge 'eel' into 'master'
Replace content from 'master' by content from 'eel' as it's the new
version based on 4a on which new development will be done.
Change-Id: I2966af7dcee59701ff3a344487c008d7e65e68ed
Signed-off-by: Loïc Collignon <loic.collignon@iot.bzh>
-rw-r--r-- | .gitignore | 2 | ||||
-rw-r--r-- | .gitmodules | 6 | ||||
-rw-r--r-- | CMakeLists.txt | 23 | ||||
m--------- | afb-helpers | 0 | ||||
-rw-r--r-- | app/CMakeLists.txt | 57 | ||||
-rw-r--r-- | app/Mixer.qml | 151 | ||||
-rw-r--r-- | app/app.pri | 12 | ||||
-rw-r--r-- | app/app.pro | 18 | ||||
-rw-r--r-- | app/main.cpp | 27 | ||||
-rw-r--r-- | app/mixer.cpp | 91 | ||||
-rw-r--r-- | app/mixer.h | 54 | ||||
-rw-r--r-- | app/paclient.cpp | 329 | ||||
-rw-r--r-- | app/paclient.h | 97 | ||||
-rw-r--r-- | app/pacontrolmodel.cpp | 208 | ||||
-rw-r--r-- | app/pacontrolmodel.h | 92 | ||||
m--------- | conf.d/app-templates | 0 | ||||
-rwxr-xr-x | conf.d/autobuild/agl/autobuild | 21 | ||||
-rwxr-xr-x | conf.d/autobuild/linux/autobuild | 67 | ||||
-rw-r--r-- | conf.d/cmake/config.cmake | 201 | ||||
-rw-r--r-- | conf.d/wgt/config.xml.in | 21 | ||||
-rw-r--r-- | conf.d/wgt/icon.svg (renamed from package/icon.svg) | 0 | ||||
-rw-r--r-- | mixer.pro | 3 | ||||
-rw-r--r-- | package/config.xml | .highlight .hll { background-color: #ffffcc }
.highlight .c { color: #888888 } /* Comment */
.highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */
.highlight .k { color: #008800; font-weight: bold } /* Keyword */
.highlight .ch { color: #888888 } /* Comment.Hashbang */
.highlight .cm { color: #888888 } /* Comment.Multiline */
.highlight .cp { color: #cc0000; font-weight: bold } /* Comment.Preproc */
.highlight .cpf { color: #888888 } /* Comment.PreprocFile */
.highlight .c1 { color: #888888 } /* Comment.Single */
.highlight .cs { color: #cc0000; font-weight: bold; background-color: #fff0f0 } /* Comment.Special */
.highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */
.highlight .ge { font-style: italic } /* Generic.Emph */
.highlight .gr { color: #aa0000 } /* Generic.Error */
.highlight .gh { color: #333333 } /* Generic.Heading */
.highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */
.highlight .go { color: #888888 } /* Generic.Output */
.highlight .gp { color: #555555 } /* Generic.Prompt */
.highlight .gs { font-weight: bold } /* Generic.Strong */
.highlight .gu { color: #666666 } /* Generic.Subheading */
.highlight .gt { color: #aa0000 } /* Generic.Traceback */
.highlight .kc { color: #008800; font-weight: bold } /* Keyword.Constant */
.highlight .kd { color: #008800; font-weight: bold } /* Keyword.Declaration */
.highlight .kn { color: #008800; font-weight: bold } /* Keyword.Namespace */
.highlight .kp { color: #008800 } /* Keyword.Pseudo */
.highlight .kr { color: #008800; font-weight: bold } /* Keyword.Reserved */
.highlight .kt { color: #888888; font-weight: bold } /* Keyword.Type */
.highlight .m { color: #0000DD; font-weight: bold } /* Literal.Number */
.highlight .s { color: #dd2200; background-color: #fff0f0 } /* Literal.String */
.highlight .na { color: #336699 } /* Name.Attribute */
.highlight .nb { color: #003388 } /* Name.Builtin */
.highlight .nc { color: #bb0066; font-weight: bold } /* Name.Class */
.highlight .no { color: #003366; font-weight: bold } /* Name.Constant */
.highlight .nd { color: #555555 } /* Name.Decorator */
.highlight .ne { color: #bb0066; font-weight: bold } /* Name.Exception */
.highlight .nf { color: #0066bb; font-weight: bold } /* Name.Function */
.highlight .nl { color: #336699; font-style: italic } /* Name.Label */
.highlight .nn { color: #bb0066; font-weight: bold } /* Name.Namespace */
.highlight .py { color: #336699; font-weight: bold } /* Name.Property */
.highlight .nt { color: #bb0066; font-weight: bold } /* Name.Tag */
.highlight .nv { color: #336699 } /* Name.Variable */
.highlight .ow { color: #008800 } /* Operator.Word */
.highlight .w { color: #bbbbbb } /* Text.Whitespace */
.highlight .mb { color: #0000DD; font-weight: bold } /* Literal.Number.Bin */
.highlight .mf { color: #0000DD; font-weight: bold } /* Literal.Number.Float */
.highlight .mh { color: #0000DD; font-weight: bold } /* Literal.Number.Hex */
.highlight .mi { color: #0000DD; font-weight: bold } /* Literal.Number.Integer */
.highlight .mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */
.highlight .sa { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Affix */
.highlight .sb { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Backtick */
.highlight .sc { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Char */
.highlight .dl { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Delimiter */
.highlight .sd { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Doc */
.highlight .s2 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Double */
.highlight .se { color: #0044dd; background-color: #fff0f0 } /* Literal.String.Escape */
.highlight .sh { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Heredoc */
.highlight .si { color: #3333bb; background-color: #fff0f0 } /* Literal.String.Interpol */
.highlight .sx { color: #22bb22; background-color: #f0fff0 } /* Literal.String.Other */
.highlight .sr { color: #008800; background-color: #fff0ff } /* Literal.String.Regex */
.highlight .s1 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Single */
.highlight .ss { color: #aa6600; background-color: #fff0f0 } /* Literal.String.Symbol */
.highlight .bp { color: #003388 } /* Name.Builtin.Pseudo */
.highlight .fm { color: #0066bb; font-weight: bold } /* Name.Function.Magic */
.highlight .vc { color: #336699 } /* Name.Variable.Class */
.highlight .vg { color: #dd7700 } /* Name.Variable.Global */
.highlight .vi { color: #3333bb } /* Name.Variable.Instance */
.highlight .vm { color: #336699 } /* Name.Variable.Magic */
.highlight .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long *//*
* Copyright (C) 2017-2018 "IoT.bzh"
* Author Sebastien Douheret <sebastien@iot.bzh>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package xdsserver
import (
"fmt"
"net/http"
"os"
"regexp"
"strconv"
"strings"
"time"
common "gerrit.automotivelinux.org/gerrit/src/xds/xds-common.git"
"gerrit.automotivelinux.org/gerrit/src/xds/xds-common.git/eows"
"gerrit.automotivelinux.org/gerrit/src/xds/xds-server.git/lib/xsapiv1"
"github.com/gin-gonic/gin"
"github.com/kr/pty"
)
var execCommandID = 1
// ExecCmd executes remotely a command
func (s *APIService) execCmd(c *gin.Context) {
var gdbPty, gdbTty *os.File
var err error
var args xsapiv1.ExecArgs
if c.BindJSON(&args) != nil {
common.APIError(c, "Invalid arguments")
return
}
// TODO: add permission ?
// Retrieve session info
sess := s.sessions.Get(c)
if sess == nil {
common.APIError(c, "Unknown sessions")
return
}
sop := sess.IOSocket
if sop == nil {
common.APIError(c, "Websocket not established")
return
}
// Allow to pass id in url (/exec/:id) or as JSON argument
idArg := c.Param("id")
if idArg == "" {
idArg = args.ID
}
if idArg == "" {
common.APIError(c, "Invalid id")
return
}
id, err := s.mfolders.ResolveID(idArg)
if err != nil {
common.APIError(c, err.Error())
return
}
f := s.mfolders.Get(id)
if f == nil {
common.APIError(c, "Unknown id")
return
}
fld := *f
prj := fld.GetConfig()
// Build command line
cmd := []string{}
// Reset by default LD_LIBRARY_PATH
// With new AGL SDK, New environment-setup-*-agl-linux file checks if
// LD_LIBRARY_PATH is set or not and not empty LD_LIBRARY_PATH is considered
// as misconfigured and prevent to use SDK
if !args.LdLibPathNoReset {
cmd = append(cmd, "unset LD_LIBRARY_PATH; ")
}
// Setup env var regarding Sdk ID (used for example to setup cross toolchain)
if envCmd := s.sdks.GetEnvCmd(args.SdkID, prj.DefaultSdk); len(envCmd) > 0 {
cmd = append(cmd, envCmd...)
cmd = append(cmd, "&&")
} else {
// It's an error if no envcmd found while a sdkid has been provided
if args.SdkID != "" {
common.APIError(c, "Unknown sdkid")
return
}
}
cmd = append(cmd, "cd", "\""+fld.GetFullPath(args.RPath)+"\"")
// FIXME - add 'exec' prevents to use syntax:
// xds-exec -l debug -c xds-config.env -- "cd build && cmake .."
// but exec is mandatory to allow to pass correctly signals
// As workaround, exec is set for now on client side (eg. in xds-gdb)
//cmd = append(cmd, "&&", "exec", args.Cmd)
cmd = append(cmd, "&&", args.Cmd)
// Process command arguments
cmdArgs := make([]string, len(args.Args)+1)
// Copy and Translate path from client to server
for _, aa := range args.Args {
if strings.Contains(aa, prj.ClientPath) {
cmdArgs = append(cmdArgs, fld.ConvPathCli2Svr(aa))
} else {
cmdArgs = append(cmdArgs, aa)
}
}
// Allocate pts if tty if used
if args.TTY {
gdbPty, gdbTty, err = pty.Open()
if err != nil {
common.APIError(c, err.Error())
return
}
s.Log.Debugf("Client command tty: %v %v\n", gdbTty.Name(), gdbTty.Name())
cmdArgs = append(cmdArgs, "--tty="+gdbTty.Name())
}
// Unique ID for each commands
if args.CmdID == "" {
args.CmdID = s.Config.ServerUID[:18] + "_" + strconv.Itoa(execCommandID)
execCommandID++
}
// Create new execution over WS context
execWS := eows.New(strings.Join(cmd, " "), cmdArgs, sop, sess.ID, args.CmdID)
execWS.Log = s.Log
execWS.OutSplit = eows.SplitChar
// Append client project dir to environment
execWS.Env = append(args.Env, "CLIENT_PROJECT_DIR="+prj.ClientPath)
// Set command execution timeout
if args.CmdTimeout == 0 {
// 0 : default timeout
// TODO get default timeout from server-config.json file
execWS.CmdExecTimeout = 24 * 60 * 60 // 1 day
} else {
execWS.CmdExecTimeout = args.CmdTimeout
}
// Define callback for input (stdin)
execWS.InputEvent = xsapiv1.ExecInEvent
execWS.InputCB = func(e *eows.ExecOverWS, bStdin []byte) ([]byte, error) {
stdin := string(bStdin)
s.Log.Debugf("STDIN <<%v>>", strings.Replace(stdin, "\n", "\\n", -1))
// Handle Ctrl-D
if len(stdin) == 1 && stdin == "\x04" {
// Close stdin
errMsg := fmt.Errorf("close stdin: %v", stdin)
return []byte{}, errMsg
}
// Set correct path
data := e.UserData
prjID := (*data)["ID"].(string)
f := s.mfolders.Get(prjID)
if f == nil {
s.Log.Errorf("InputCB: Cannot get folder ID %s", prjID)
} else {
// Translate paths from client to server
stdin = (*f).ConvPathCli2Svr(stdin)
}
return []byte(stdin), nil
}
// Define callback for output (stdout+stderr)
execWS.OutputCB = func(e *eows.ExecOverWS, bStdout, bStderr []byte) {
stdout := string(bStdout)
stderr := string(bStderr)
// IO socket can be nil when disconnected
so := s.sessions.IOSocketGet(e.Sid)
if so == nil {
s.Log.Infof("%s not emitted: WS closed (sid:%s, CmdID:%s)", xsapiv1.ExecOutEvent, e.Sid, e.CmdID)
return
}
// Retrieve project ID and RootPath
data := e.UserData
prjID := (*data)["ID"].(string)
gdbServerTTY := (*data)["gdbServerTTY"].(string)
f := s.mfolders.Get(prjID)
if f == nil {
s.Log.Errorf("OutputCB: Cannot get folder ID %s", prjID)
} else {
// Translate paths from server to client
stdout = (*f).ConvPathSvr2Cli(stdout)
stderr = (*f).ConvPathSvr2Cli(stderr)
}
s.Log.Debugf("%s emitted - WS sid[4:] %s - id:%s - prjID:%s", xsapiv1.ExecOutEvent, e.Sid[4:], e.CmdID, prjID)
if stdout != "" {
s.Log.Debugf("STDOUT <<%v>>", strings.Replace(stdout, "\n", "\\n", -1))
}
if stderr != "" {
s.Log.Debugf("STDERR <<%v>>", strings.Replace(stderr, "\n", "\\n", -1))
}
// FIXME replace by .BroadcastTo a room
err := (*so).Emit(xsapiv1.ExecOutEvent, xsapiv1.ExecOutMsg{
CmdID: e.CmdID,
Timestamp: time.Now().String(),
Stdout: stdout,
Stderr: stderr,
})
if err != nil {
s.Log.Errorf("WS Emit : %v", err)
}
// XXX - Workaround due to gdbserver bug that doesn't redirect
// inferior output (https://bugs.eclipse.org/bugs/show_bug.cgi?id=437532#c13)
if gdbServerTTY == "workaround" && len(stdout) > 1 && stdout[0] == '&' {
// Extract and cleanup string like &"bla bla\n"
re := regexp.MustCompile("&\"(.*)\"")
rer := re.FindAllStringSubmatch(stdout, -1)
out := ""
if rer != nil && len(rer) > 0 {
for _, o := range rer {
if len(o) >= 1 {
out = strings.Replace(o[1], "\\n", "\n", -1)
out = strings.Replace(out, "\\r", "\r", -1)
out = strings.Replace(out, "\\t", "\t", -1)
s.Log.Debugf("STDOUT INFERIOR: <<%v>>", out)
err := (*so).Emit(xsapiv1.ExecInferiorOutEvent, xsapiv1.ExecOutMsg{
CmdID: e.CmdID,
Timestamp: time.Now().String(),
Stdout: out,
Stderr: "",
})
if err != nil {
s.Log.Errorf("WS Emit : %v", err)
}
}
}
} else {
s.Log.Errorf("INFERIOR out parsing error: stdout=<%v>", stdout)
}
}
}
// Define callback for output
execWS.ExitCB = func(e *eows.ExecOverWS, code int, err error) {
s.Log.Debugf("Command [Cmd ID %s] exited: code %d, error: %v", e.CmdID, code, err)
defer LockXdsUpdateCounter(s.Context, false)
// Close client tty
defer func() {
if gdbPty != nil {
gdbPty.Close()
}
if gdbTty != nil {
gdbTty.Close()
}
}()
// IO socket can be nil when disconnected
so := s.sessions.IOSocketGet(e.Sid)
if so == nil {
s.Log.Infof("%s not emitted - WS closed (id:%s)", xsapiv1.ExecExitEvent, e.CmdID)
return
}
// Retrieve project ID and RootPath
data := e.UserData
prjID := (*data)["ID"].(string)
exitImm := (*data)["ExitImmediate"].(bool)
// XXX - workaround to be sure that Syncthing detected all changes
if err := s.mfolders.ForceSync(prjID); err != nil {
s.Log.Errorf("Error while syncing folder %s: %v", prjID, err)
}
if !exitImm {
// Wait end of file sync
// FIXME pass as argument
tmo := 60
for t := tmo; t > 0; t-- {
s.Log.Debugf("Wait file in-sync for %s (%d/%d)", prjID, t, tmo)
if sync, err := s.mfolders.IsFolderInSync(prjID); sync || err != nil {
if err != nil {
s.Log.Errorf("ERROR IsFolderInSync (%s): %v", prjID, err)
}
break
}
time.Sleep(time.Second)
}
s.Log.Debugf("OK file are synchronized.")
}
// FIXME replace by .BroadcastTo a room
errSoEmit := (*so).Emit(xsapiv1.ExecExitEvent, xsapiv1.ExecExitMsg{
CmdID: e.CmdID,
Timestamp: time.Now().String(),
Code: code,
Error: err,
})
if errSoEmit != nil {
s.Log.Errorf("WS Emit : %v", errSoEmit)
}
}
// User data (used within callbacks)
data := make(map[string]interface{})
data["ID"] = prj.ID
data["ExitImmediate"] = args.ExitImmediate
if args.TTY && args.TTYGdbserverFix {
data["gdbServerTTY"] = "workaround"
} else {
data["gdbServerTTY"] = ""
}
execWS.UserData = &data
// Start command execution
s.Log.Infof("Execute [Cmd ID %s]: %v %v", execWS.CmdID, execWS.Cmd, execWS.Args)
LockXdsUpdateCounter(s.Context, true)
err = execWS.Start()
if err != nil {
LockXdsUpdateCounter(s.Context, false)
common.APIError(c, err.Error())
return
}
c.JSON(http.StatusOK, xsapiv1.ExecResult{Status: "OK", CmdID: execWS.CmdID})
}
// ExecCmd executes remotely a command
func (s *APIService) execSignalCmd(c *gin.Context) {
var args xsapiv1.ExecSignalArgs
if c.BindJSON(&args) != nil {
common.APIError(c, "Invalid arguments")
return
}
s.Log.Debugf("Signal %s for command ID %s", args.Signal, args.CmdID)
e := eows.GetEows(args.CmdID)
if e == nil {
common.APIError(c, "unknown cmdID")
return
}
err := e.Signal(args.Signal)
if err != nil {
common.APIError(c, err.Error())
return
}
c.JSON(http.StatusOK, xsapiv1.ExecSigResult{Status: "OK", CmdID: args.CmdID})
}
|