func (repo *cliReader) RootCommit() (rootCommit string, err error) { cmd := exec.Command("git", "rev-list", "--max-parents=0", "HEAD") cmd.Dir = repo.repoPath output, err := cmd.Output() if bytes.Count(output, []byte{'\n'}) > 1 { log.Critical("More than one root commit present") } rootCommit = string(bytes.TrimSpace(output)) return }
// Branches reads all branches in a git repo func (repo *cliReader) Branches() (branches []*GitChange, err error) { cmd := exec.Command("git", "branch", "-v", "--abbrev=40") cmd.Dir = repo.repoPath out, err := cmd.CombinedOutput() if err != nil { return nil, err } rootCommit, err := repo.RootCommit() if err != nil { log.Critical("Unable to get root commit") } for _, m := range branchLineRE.FindAllStringSubmatch(string(out), -1) { branches = append(branches, &GitChange{ RefName: m[2], Current: m[3], CheckedOut: m[1] == "*", RootCommit: rootCommit, RepoName: repo.Name(), }) } return }
// NetIO shares GitChanges on toNet with the network via a multicast group. It // will pass on GitChanges from the network via fromNet. It uniques the daemon // instance by changing the .Name member to be name@<host IP>/<original .Name) func NetIO(l log.Logger, repo Repo, addr *net.UDPAddr, fromNet, toNet chan GitChange) { var ( err error recvConn, sendConn *net.UDPConn // UDP connections to allow us to send and receive change updates ) l.Info("Joining %v multicast(%t) group", addr, addr.IP.IsMulticast()) if recvConn, sendConn, err = establishConnPair(addr); err != nil { l.Critical("Error joining listening: %s\n", addr, err) return } l.Info("Successfully joined %v multicast(%t) group", addr, addr.IP.IsMulticast()) defer recvConn.Close() defer sendConn.Close() hostIp := sendConn.LocalAddr().(*net.UDPAddr).IP.String() term := false defer func() { term = true }() rawFromNet := make(chan []byte, 128) go func() { for !term { b := make([]byte, 1024) if n, err := recvConn.Read(b); err != nil { l.Critical("Cannot read socket: %s", err) continue } else { rawFromNet <- b[:n] } } }() for { select { case req, ok := <-toNet: if !ok { return } req.User = repo.User() req.HostIp = hostIp l.Info("Sending %+v", req) buf := &bytes.Buffer{} enc := gob.NewEncoder(buf) if err := enc.Encode(req); err != nil { l.Critical("%s", err) continue } l.Fine("Sending %+v", buf.Bytes()) if _, err := sendConn.Write(buf.Bytes()); err != nil { l.Critical("%s", err) continue } case resp := <-rawFromNet: var change GitChange dec := gob.NewDecoder(bytes.NewReader(resp)) if err := dec.Decode(&change); err != nil { l.Critical("%s", err) continue } else { l.Debug("received %+v", change) } if rootCommit, err := repo.RootCommit(); err != nil { log.Critical("Error getting root commit") } else { if (repo.User() != change.User) && (rootCommit == change.RootCommit) { fromNet <- change } } } } }