Example #1
0
// PollDirectory will poll a git repo.
// It will look for changes to branches and tags including creation and
// deletion.
func PollDirectory(l log.Logger, dirName string, repo Repo, changes chan GitChange, period time.Duration) {
	l.Info("Watching %s as %s\n", repo, dirName)
	defer l.Info("Stopped watching %s as %s\n", repo, dirName)

	prev := make(map[string]*GitChange) // last seen ref status

	// Every poll period, get the list of branches.
	// For those seen before, fill in previous and currect SHA in change. Remove
	// from prev set.
	// For those that are new, fill in data.
	// For remaining entries in prev set, these are deleted. Send them with
	// current as empty.
	for firstAttempt := true; ; firstAttempt = false {
		var (
			next     = make(map[string]*GitChange) // currently seen refs, becomes prev set
			branches []*GitChange                  // working set of branches
			err      error
		)

		// run cmd every period, except on the first try
		if !firstAttempt {
			time.Sleep(period)
		}

		if branches, err = repo.Branches(); err != nil {
			l.Critical("Cannot get branch list for %s: %s", repo, err)
			continue
		}
		for _, branch := range branches {
			if strings.HasPrefix(branch.RefName, "gitsync-") {
				continue
			}
			var (
				old, seenBefore  = prev[branch.RefName]
				existsAndChanged = seenBefore && (old.Current != branch.Current || old.CheckedOut != branch.CheckedOut)
			)

			branch.RepoName = path.Base(dirName)
			next[branch.RefName] = branch
			if existsAndChanged {
				branch.Prev = old.Current
			}

			// share changes and new branches
			if !seenBefore || existsAndChanged {
				l.Info("sending local change for %s %+v", repo, branch)
				changes <- *branch
			}

			// Cleanup any branch we have seen before, and handled above
			if seenBefore {
				delete(prev, branch.RefName)
			}
		}

		// report remaining branches in prev as deleted
		// Note: Use the prev set object since we have no current one to play with
		for _, old := range prev {
			old.Prev = old.Current
			old.Current = ""
			old.CheckedOut = false

			l.Info("sending local delete for %s %+v", repo, old)
			changes <- *old
		}

		prev = next
	}
}
Example #2
0
// 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
				}
			}
		}
	}
}