X-Git-Url: http://www.git.cypherpunks.ru/?a=blobdiff_plain;f=run.go;h=e40ad1d5d5e4b65a262ea385b4a0e10df3274fa6;hb=b2eef1c806af5802089517b8c86abc65edfe574d;hp=0f7277bfd34313daf56c01e3b60ab4dee272f922;hpb=f8a8a335216a6ec9aa6119d473d2f6aeb43958ca;p=goredo.git diff --git a/run.go b/run.go index 0f7277b..e40ad1d 100644 --- a/run.go +++ b/run.go @@ -29,7 +29,6 @@ import ( "os" "os/exec" "path" - "strconv" "strings" "sync" "syscall" @@ -57,16 +56,15 @@ const ( ) var ( - Trace bool = false NoSync bool = false StderrKeep bool = false StderrSilent bool = false StderrPrefix string Jobs sync.WaitGroup - flagTrace = flag.Bool("x", false, "trace current target (sh -x) (set REDO_TRACE=1 for others too)") - flagStderrKeep = flag.Bool("logs", false, "keep job's stderr (REDO_LOGS=1)") - flagStderrSilent = flag.Bool("silent", false, "do not print job's stderr (REDO_SILENT=1)") + flagTrace = flag.Bool("x", false, fmt.Sprintf("trace current target (sh -x) (set %s=1 for all others)", EnvTrace)) + flagStderrKeep = flag.Bool("logs", false, fmt.Sprintf("keep job's stderr (%s=1)", EnvStderrKeep)) + flagStderrSilent = flag.Bool("silent", false, fmt.Sprintf("do not print job's stderr (%s=1)", EnvStderrSilent)) ) type RunErr struct { @@ -103,16 +101,6 @@ func mkdirs(pth string) error { return os.MkdirAll(pth, os.FileMode(0777)) } -func tempsuffix() string { - return strconv.FormatInt((time.Now().UnixNano()+int64(os.Getpid()))&0xFFFFFFFF, 16) -} - -func tempfile(dir, prefix string) (*os.File, error) { - // It respects umask, unlike ioutil.TempFile - name := path.Join(dir, TmpPrefix+prefix+"."+tempsuffix()) - return os.OpenFile(name, os.O_RDWR|os.O_CREATE|os.O_EXCL, os.FileMode(0666)) -} - func isModified(cwd, redoDir, tgt string) (bool, string, error) { fdDep, err := os.Open(path.Join(redoDir, tgt+DepSuffix)) if err != nil { @@ -165,7 +153,7 @@ func syncDir(dir string) error { return err } -func runScript(tgtOrig string, errs chan error) error { +func runScript(tgtOrig string, errs chan error, traced bool) error { cwd, tgt := cwdAndTgt(tgtOrig) redoDir := path.Join(cwd, RedoDir) if err := mkdirs(redoDir); err != nil { @@ -194,14 +182,20 @@ func runScript(tgtOrig string, errs chan error) error { fdLock.Close() return TgtErr{tgtOrig, err} } - trace(CDebug, "waiting: %s", tgtOrig) Jobs.Add(1) + trace(CDebug, "waiting: %s", tgtOrig) + if FdStatus != nil { + FdStatus.Write([]byte{StatusWait}) + } go func() { defer Jobs.Done() trace(CLock, "LOCK_EX: %s", fdLock.Name()) unix.Flock(int(fdLock.Fd()), unix.LOCK_EX) lockRelease() trace(CDebug, "waiting done: %s", tgtOrig) + if FdStatus != nil { + FdStatus.Write([]byte{StatusWaited}) + } var depInfo *DepInfo fdDep, err := os.Open(path.Join(redoDir, tgt+DepSuffix)) if err != nil { @@ -270,10 +264,6 @@ func runScript(tgtOrig string, errs chan error) error { cleanup() return TgtErr{tgtOrig, errors.New("no .do found")} } - if err = writeDep(fdDep, cwd, doFile); err != nil { - cleanup() - return TgtErr{tgtOrig, err} - } // Determine basename and DIRPREFIX ents := strings.Split(cwd, "/") @@ -284,52 +274,32 @@ func runScript(tgtOrig string, errs chan error) error { cwd = path.Join(cwd, "..") } cwd = path.Clean(cwd) + doFilePath := path.Join(cwd, doFile) basename := tgt runErr := RunErr{Tgt: tgtOrig} if strings.HasPrefix(doFile, "default.") { basename = tgt[:len(tgt)-(len(doFile)-len("default.")-len(".do"))-1] runErr.DoFile = doFile } + + if err = writeDep(fdDep, cwd, doFile); err != nil { + cleanup() + return TgtErr{tgtOrig, err} + } trace(CWait, "%s", runErr.Name()) - doFile = path.Base(doFile) // Prepare command line var cmdName string var args []string - if err = unix.Access(path.Join(cwd, doFile), unix.X_OK); err == nil { - // Ordinary executable file - cmdName = doFile + if err = unix.Access(doFilePath, unix.X_OK); err == nil { + cmdName = doFilePath args = make([]string, 0, 3) } else { - fd, err := os.Open(path.Join(cwd, doFile)) - if err != nil { - cleanup() - return TgtErr{tgtOrig, err} - } - buf := make([]byte, 512) - n, err := fd.Read(buf) - if err != nil { - cleanup() - return TgtErr{tgtOrig, err} - } - if n > 3 && string(buf[:3]) == "#!/" { - // Shebanged - t := string(buf[2:n]) - nlIdx := strings.Index(t, "\n") - if nlIdx == -1 { - cleanup() - return TgtErr{tgtOrig, errors.New("not fully read shebang")} - } - args = strings.Split(t[:nlIdx], " ") - cmdName, args = args[0], args[1:] + cmdName = "/bin/sh" + if traced { + args = append(args, "-ex") } else { - // Shell - cmdName = "/bin/sh" - if Trace { - args = append(args, "-ex") - } else { - args = append(args, "-e") - } + args = append(args, "-e") } args = append(args, doFile) } @@ -355,10 +325,19 @@ func runScript(tgtOrig string, errs chan error) error { "%s=%s", EnvStderrPrefix, childStderrPrefix, )) - cmd.ExtraFiles = append(cmd.ExtraFiles, fdDep) fdNum := 0 + cmd.ExtraFiles = append(cmd.ExtraFiles, fdDep) cmd.Env = append(cmd.Env, fmt.Sprintf("%s=%d", EnvDepFd, 3+fdNum)) fdNum++ + + if FdStatus == nil { + cmd.Env = append(cmd.Env, fmt.Sprintf("%s=NO", EnvStatusFd)) + } else { + cmd.ExtraFiles = append(cmd.ExtraFiles, FdStatus) + cmd.Env = append(cmd.Env, fmt.Sprintf("%s=%d", EnvStatusFd, 3+fdNum)) + fdNum++ + } + if JSR == nil { // infinite jobs cmd.Env = append(cmd.Env, fmt.Sprintf("%s=NO", EnvJSFd)) @@ -395,6 +374,9 @@ func runScript(tgtOrig string, errs chan error) error { Jobs.Add(1) go func() { jsAcquire(shCtx) + if FdStatus != nil { + FdStatus.Write([]byte{StatusRun}) + } defer func() { jsRelease(shCtx) lockRelease() @@ -407,6 +389,9 @@ func runScript(tgtOrig string, errs chan error) error { os.Remove(fdStdout.Name()) os.Remove(tmpPath) os.Remove(fdLock.Name()) + if FdStatus != nil { + FdStatus.Write([]byte{StatusDone}) + } Jobs.Done() }() started := time.Now() @@ -434,7 +419,9 @@ func runScript(tgtOrig string, errs chan error) error { } if fdStderr != nil { tai64nNow(ts) + LogMutex.Lock() fmt.Fprintf(fdStderr, "@%s %s\n", hex.EncodeToString(ts[:]), line) + LogMutex.Unlock() } if StderrSilent { continue