Exemple #1
0
// WriteLock writes the lock as YAML.
//
// Params:
//	- lockfile: A *cfg.Lockfile to render.
// 	- out (io.Writer): An output stream to write to. Default is os.Stdout.
func WriteLock(c cookoo.Context, p *cookoo.Params) (interface{}, cookoo.Interrupt) {
	skip := p.Get("skip", false).(bool)
	if skip {
		return false, nil
	}

	lockfile := p.Get("lockfile", nil).(*cfg.Lockfile)

	Info("Writing glide.lock file")

	data, err := lockfile.Marshal()
	if err != nil {
		return nil, err
	}

	var out io.Writer
	file, err := os.Create("glide.lock")
	if err != nil {
		return false, err
	}
	defer file.Close()
	out = io.Writer(file)
	out.Write(data)

	return true, nil
}
Exemple #2
0
// ExecCmd executes a system command  inside vendor
func ExecCmd(c cookoo.Context, p *cookoo.Params) (interface{}, cookoo.Interrupt) {
	args := p.Get("args", nil).(cli.Args)

	if len(args) == 0 {
		return nil, fmt.Errorf("No command to execute")
	}

	gopath, err := VendorPath(c)
	if err != nil {
		return false, err
	}

	err = os.Setenv("GOPATH", gopath)
	if err != nil {
		return false, err
	}

	path := os.Getenv("PATH")
	err = os.Setenv("PATH", gopath+"/bin:"+path)
	if err != nil {
		return false, err
	}

	cmd := exec.Command(args[0], args[1:]...)
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	err = cmd.Run()

	return true, nil
}
Exemple #3
0
// MergeToYaml converts a Config object and a yaml.File to a single yaml.File.
//
// Params:
//	- conf (*Config): The configuration to merge.
//	- overwriteImports (bool, default true): If this is true, old config will
//		overwritten. If false, we attempt to merge the old and new config, with
//		preference to the old.
//
// Returns:
//	- The root yaml.Node of the modified config.
//
// Uses:
//	- cxt.Get("yaml.File") as the source for the YAML file.
func MergeToYaml(c cookoo.Context, p *cookoo.Params) (interface{}, cookoo.Interrupt) {
	root := c.Get("yaml.File", nil).(*yaml.File).Root
	cfg := p.Get("conf", nil).(*Config)
	overwrite := p.Get("overwriteImports", true).(bool)

	rootMap, ok := root.(yaml.Map)
	if !ok {
		return nil, fmt.Errorf("Expected root node to be a map.")
	}

	if len(cfg.Name) > 0 {
		rootMap["package"] = yaml.Scalar(cfg.Name)
	}
	if cfg.InCommand != "" {
		rootMap["incmd"] = yaml.Scalar(cfg.InCommand)
	}

	if overwrite {
		// Imports
		imports := make([]yaml.Node, len(cfg.Imports))
		for i, imp := range cfg.Imports {
			imports[i] = imp.ToYaml()
		}
		rootMap["import"] = yaml.List(imports)
	} else {
		var err error
		rootMap, err = mergeImports(rootMap, cfg)
		if err != nil {
			Warn("Problem merging imports: %s\n", err)
		}
	}

	return root, nil
}
Exemple #4
0
/**
 * Perform authentication.
 *
 * Params:
 * 	- realm (string): The name of the realm. (Default: "web")
 * 	- datasource (string): The name of the datasource that should be used to authenticate.
 * 	  This datasource must be an `auth.UserDatasource`. (Default: "auth.UserDatasource")
 *
 * Context:
 * 	- http.Request (*http.Request): The HTTP request. This is usually placed into the
 * 	context for you.
 * 	- http.ResponseWriter (http.ResponseWriter): The response. This is usually placed
 * 	 into the context for you.
 *
 * Datasource:
 * 	- An auth.UserDatasource. By default, this will look for a datasource named
 * 	  "auth.UserDatasource". This can be overridden by the `datasource` param.
 *
 * Returns:
 * 	- True if the user authenticated. If not, this will send a 401 and then stop
 * 	  the current chain.
 */
func Basic(c cookoo.Context, p *cookoo.Params) (interface{}, cookoo.Interrupt) {
	realm := p.Get("realm", "web").(string)
	dsName := p.Get("datasource", "auth.UserDatasource").(string)

	req := c.Get("http.Request", nil).(*http.Request)
	res := c.Get("http.ResponseWriter", nil).(http.ResponseWriter)

	ds := c.Datasource(dsName).(UserDatasource)

	authz := strings.TrimSpace(req.Header.Get("Authorization"))
	if len(authz) == 0 || !strings.Contains(authz, "Basic ") {
		return sendUnauthorized(realm, res)
	}

	user, pass, err := parseBasicString(authz)
	if err != nil {
		c.Logf("info", "Basic authentication parsing failed: %s", err)
		return sendUnauthorized(realm, res)
	}

	ok, err := ds.AuthUser(user, pass)
	if !ok {
		if err != nil {
			c.Logf("info", "Basic authentication caused an error: %s", err)
		}
		return sendUnauthorized(realm, res)
	}

	return ok, err
}
Exemple #5
0
// ListDeps lists all of the dependencies of the current project.
//
// Params:
//
// Returns:
//
func ListDeps(c cookoo.Context, p *cookoo.Params) (interface{}, cookoo.Interrupt) {
	buildContext, err := GetBuildContext()
	if err != nil {
		return nil, err
	}
	basedir := p.Get("dir", ".").(string)
	myName := guessPackageName(buildContext, basedir)

	basedir, err = filepath.Abs(basedir)
	if err != nil {
		return nil, err
	}

	direct := map[string]*pinfo{}
	d := walkDeps(buildContext, basedir, myName)
	for _, i := range d {
		listDeps(buildContext, direct, i, basedir)
	}

	sortable := make([]string, len(direct))
	i := 0
	for k := range direct {
		sortable[i] = k
		i++
	}

	sort.Strings(sortable)

	for _, k := range sortable {
		t := direct[k].PType
		fmt.Printf("%s (Location: %s)\n", k, ptypeString(t))
	}

	return nil, nil
}
Exemple #6
0
// ParallelBuild runs multiple docker builds at the same time.
//
// Params:
//	-images ([]BuildImg): Images to build
// 	-alwaysFetch (bool): Default false. If set to true, this will always fetch
// 		the Docker image even if it already exists in the registry.
//
// Returns:
//
// 	- Waiter: A *sync.WaitGroup that is waiting for the docker downloads to finish.
//
// Context:
//
// This puts 'ParallelBuild.failN" (int) into the context to indicate how many failures
// occurred during fetches.
func ParallelBuild(c cookoo.Context, p *cookoo.Params) (interface{}, cookoo.Interrupt) {
	images := p.Get("images", []BuildImg{}).([]BuildImg)

	var wg sync.WaitGroup
	var m sync.Mutex
	var fails int

	for _, img := range images {
		img := img

		// HACK: ensure "docker build" is serialized by allowing only one entry in
		// the WaitGroup. This works around the "simultaneous docker pull" bug.
		wg.Wait()
		wg.Add(1)
		safely.GoDo(c, func() {
			log.Infof(c, "Starting build for %s (tag: %s)", img.Path, img.Tag)
			if _, err := buildImg(c, img.Path, img.Tag); err != nil {
				log.Errf(c, "Failed to build docker image: %s", err)
				m.Lock()
				fails++
				m.Unlock()
			}
			wg.Done()
		})

	}

	// Number of failures.
	c.Put("ParallelBuild.failN", fails)

	return &wg, nil
}
Exemple #7
0
// Watch watches a given path, and executes a git check-repos for each event.
//
// It starts the watcher and then returns. The watcher runs on its own
// goroutine. To stop the watching, send the returned channel a bool.
//
// Params:
// - client (Watcher): An Etcd client.
// - path (string): The path to watch
//
// Returns:
// 	- chan bool: Send this a message to stop the watcher.
func Watch(c cookoo.Context, p *cookoo.Params) (interface{}, cookoo.Interrupt) {
	// etcdctl -C $ETCD watch --recursive /deis/services
	path := p.Get("path", "/deis/services").(string)
	cli, ok := p.Has("client")
	if !ok {
		return nil, errors.New("No etcd client found.")
	}
	client := cli.(Watcher)

	// Stupid hack because etcd watch seems to be broken, constantly complaining
	// that the JSON it received is malformed.
	safely.GoDo(c, func() {
		for {
			response, err := client.Watch(path, 0, true, nil, nil)
			if err != nil {
				log.Errf(c, "Etcd Watch failed: %s", err)
				time.Sleep(50 * time.Millisecond)
				continue
			}

			if response.Node == nil {
				log.Infof(c, "Unexpected Etcd message: %v", response)
			}
			git := exec.Command("/home/git/check-repos")
			if out, err := git.CombinedOutput(); err != nil {
				log.Errf(c, "Failed git check-repos: %s", err)
				log.Infof(c, "Output: %s", out)
			}
		}

	})

	return nil, nil

}
Exemple #8
0
// ListDeps lists all of the dependencies of the current project.
//
// Params:
//
// Returns:
//
func ListDeps(c cookoo.Context, p *cookoo.Params) (interface{}, cookoo.Interrupt) {
	basedir := p.Get("dir", ".").(string)
	myName := guessPackageName(basedir)

	var err error
	basedir, err = filepath.Abs(basedir)
	if err != nil {
		return nil, err
	}

	direct := map[string]bool{}
	d := walkDeps(basedir, myName)
	for _, i := range d {
		listDeps(direct, i, basedir)
	}

	sortable := make([]string, len(direct))
	i := 0
	for k, _ := range direct {
		sortable[i] = k
		i++
	}

	sort.Strings(sortable)

	for _, k := range sortable {
		dec := "no"
		if direct[k] {
			dec = "yes"
		}
		fmt.Printf("%s (Present: %s)\n", k, dec)
	}

	return nil, nil
}
Exemple #9
0
// Subscribe allows an request to subscribe to topic updates.
//
// Params:
// 	- topic (string): The topic to subscribe to.
// 	-
//
// Returns:
//
func Subscribe(c cookoo.Context, p *cookoo.Params) (interface{}, cookoo.Interrupt) {
	medium, err := getMedium(c)
	if err != nil {
		return nil, &cookoo.FatalError{"No medium."}
	}
	topic := p.Get("topic", "").(string)
	if len(topic) == 0 {
		return nil, errors.New("No topic is set.")
	}

	rw := c.Get("http.ResponseWriter", nil).(ResponseWriterFlusher)
	clientGone := rw.(http.CloseNotifier).CloseNotify()

	sub := NewSubscription(rw)
	t := fetchOrCreateTopic(medium, topic, true, DefaultMaxHistory)
	t.Subscribe(sub)

	defer func() {
		t.Unsubscribe(sub)
		sub.Close()
	}()

	sub.Listen(clientGone)

	return nil, nil
}
Exemple #10
0
// Watch watches a given path, and executes a git check-repos for each event.
//
// It starts the watcher and then returns. The watcher runs on its own
// goroutine. To stop the watching, send the returned channel a bool.
//
// Params:
// - client (Watcher): An Etcd client.
// - path (string): The path to watch
func Watch(c cookoo.Context, p *cookoo.Params) (interface{}, cookoo.Interrupt) {

	// etcdctl -C $ETCD watch --recursive /deis/services
	path := p.Get("path", "/deis/services").(string)
	cli := p.Get("client", nil).(client.Client)
	k := client.NewKeysAPI(cli)

	watcher := k.Watcher(path, &client.WatcherOptions{Recursive: true})

	safely.GoDo(c, func() {
		for {
			// TODO: We should probably add cancellation support.
			response, err := watcher.Next(dctx())
			if err != nil {
				log.Errf(c, "Etcd Watch failed: %s", err)
			}
			if response.Node == nil {
				log.Infof(c, "Unexpected Etcd message: %v", response)
			}
			git := exec.Command("/home/git/check-repos")
			if out, err := git.CombinedOutput(); err != nil {
				log.Errf(c, "Failed git check-repos: %s", err)
				log.Infof(c, "Output: %s", out)
			}
		}
	})
	return nil, nil
}
Exemple #11
0
// ParseHostKeys parses the host key files.
//
// By default it looks in /etc/ssh for host keys of the patterh ssh_host_{{TYPE}}_key.
//
// Params:
// 	- keytypes ([]string): Key types to parse. Defaults to []string{rsa, dsa, ecdsa}
// 	- enableV1 (bool): Allow V1 keys. By default this is disabled.
// 	- path (string): Override the lookup pattern. If %s, it will be replaced with the keytype.
//
// Returns:
// 	[]ssh.Signer
func ParseHostKeys(c cookoo.Context, p *cookoo.Params) (interface{}, cookoo.Interrupt) {
	log.Debugf(c, "Parsing ssh host keys")
	hostKeyTypes := p.Get("keytypes", []string{"rsa", "dsa", "ecdsa"}).([]string)
	pathTpl := p.Get("path", "/etc/ssh/ssh_host_%s_key").(string)
	hostKeys := make([]ssh.Signer, 0, len(hostKeyTypes))
	for _, t := range hostKeyTypes {
		path := fmt.Sprintf(pathTpl, t)

		if key, err := ioutil.ReadFile(path); err == nil {
			if hk, err := ssh.ParsePrivateKey(key); err == nil {
				log.Infof(c, "Parsed host key %s.", path)
				hostKeys = append(hostKeys, hk)
			} else {
				log.Errf(c, "Failed to parse host key %s (skipping): %s", path, err)
			}
		}
	}
	if c.Get("enableV1", false).(bool) {
		path := "/etc/ssh/ssh_host_key"
		if key, err := ioutil.ReadFile(path); err != nil {
			log.Errf(c, "Failed to read ssh_host_key")
		} else if hk, err := ssh.ParsePrivateKey(key); err == nil {
			log.Infof(c, "Parsed host key %s.", path)
			hostKeys = append(hostKeys, hk)
		} else {
			log.Errf(c, "Failed to parse host key %s: %s", path, err)
		}
	}
	return hostKeys, nil
}
Exemple #12
0
// Push pushes an image to the registry.
//
// This finds the appropriate registry by looking it up in etcd.
//
// Params:
// - client (etcd.Getter): Client to do etcd lookups.
// - tag (string): Tag to push.
//
// Returns:
//
func Push(c cookoo.Context, p *cookoo.Params) (interface{}, cookoo.Interrupt) {
	// docker tag deis/slugrunner:lastest HOST:PORT/deis/slugrunner:latest
	// docker push HOST:PORT/deis/slugrunner:latest
	client := p.Get("client", nil).(etcd.Getter)

	host, err := client.Get("/deis/registry/host", false, false)
	if err != nil || host.Node == nil {
		return nil, err
	}
	port, err := client.Get("/deis/registry/port", false, false)
	if err != nil || host.Node == nil {
		return nil, err
	}

	registry := host.Node.Value + ":" + port.Node.Value
	tag := p.Get("tag", "").(string)

	log.Infof(c, "Pushing %s to %s. This may take some time.", tag, registry)
	rem := path.Join(registry, tag)

	out, err := exec.Command("docker", "tag", "-f", tag, rem).CombinedOutput()
	if err != nil {
		log.Warnf(c, "Failed to tag %s on host %s: %s (%s)", tag, rem, err, out)
	}
	out, err = exec.Command("docker", "-D", "push", rem).CombinedOutput()

	if err != nil {
		log.Warnf(c, "Failed to push %s to host %s: %s (%s)", tag, rem, err, out)
		return nil, err
	}
	log.Infof(c, "Finished pushing %s to %s.", tag, registry)
	return nil, nil
}
Exemple #13
0
// Template is a template-based text formatter.
//
// This uses the core `text/template` to process a given string template.
//
// Params
// 	- template (string): A template string.
// 	- template.Context (bool): If true, the context will be placed into the
// 		template renderer as 'Cxt', and can be used as `{{.Cxt.Foo}}`. False
// 		by default.
// 	- ... (interface{}): Values passed into the template.
//
// Conventionally, template variables should start with an initial capital.
//
// Returns a formatted string.
func Template(c cookoo.Context, p *cookoo.Params) (interface{}, cookoo.Interrupt) {
	format := cookoo.GetString("template", "", p)
	withCxt := cookoo.GetBool("template.Context", false, p)

	name := fmt.Sprintf("%x", md5.Sum([]byte(format)))

	//c.Logf("debug", "Template %s is '%s'\n", name, format)

	tpl, err := template.New(name).Parse(format)
	if err != nil {
		return "", err
	}

	data := p.AsMap()
	if withCxt {
		//c.Logf("debug", "Adding context.")
		data["Cxt"] = c.AsMap()
	}

	var out bytes.Buffer
	if err := tpl.Execute(&out, data); err != nil {
		return "", err
	}

	return out.String(), nil
}
Exemple #14
0
// ParallelBuild runs multiple docker builds at the same time.
//
// Params:
//	-images ([]BuildImg): Images to build
// 	-alwaysFetch (bool): Default false. If set to true, this will always fetch
// 		the Docker image even if it already exists in the registry.
//
// Returns:
//
// 	- Waiter: A *sync.WaitGroup that is waiting for the docker downloads to finish.
//
// Context:
//
// This puts 'ParallelBuild.failN" (int) into the context to indicate how many failures
// occurred during fetches.
func ParallelBuild(c cookoo.Context, p *cookoo.Params) (interface{}, cookoo.Interrupt) {
	images := p.Get("images", []BuildImg{}).([]BuildImg)

	var wg sync.WaitGroup
	var m sync.Mutex
	var fails int

	for _, img := range images {
		img := img
		wg.Add(1)
		safely.GoDo(c, func() {
			log.Infof(c, "Starting build for %s (tag: %s)", img.Path, img.Tag)
			if _, err := buildImg(c, img.Path, img.Tag); err != nil {
				log.Errf(c, "Failed to build docker image: %s", err)
				m.Lock()
				fails++
				m.Unlock()
			}
			wg.Done()
		})

	}

	// Number of failures.
	c.Put("ParallelBuild.failN", fails)

	return &wg, nil
}
Exemple #15
0
// RemoveMemberByName removes a member whose name matches the given.
//
// Params:
// 	- client(client.Client): An etcd client
//	- name (string): The name to remove
// Returns:
//	true if the member was found, false otherwise.
func RemoveMemberByName(c cookoo.Context, p *cookoo.Params) (interface{}, cookoo.Interrupt) {
	cli := p.Get("client", nil).(client.Client)
	name := p.Get("name", "____").(string)
	mem := client.NewMembersAPI(cli)

	members, err := mem.List(dctx())
	if err != nil {
		log.Errf(c, "Could not get a list of members: %s", err)
		return false, err
	}

	remIDs := []string{}
	for _, member := range members {
		if member.Name == name {
			log.Infof(c, "Removing member %s (ID: %s)", name, member.ID)
			// If this is synchronizable, we should do it in parallel.
			if err := mem.Remove(dctx(), member.ID); err != nil {
				log.Errf(c, "Failed to remove member: %s", err)
				return len(remIDs) > 0, err
			}
			remIDs = append(remIDs, member.ID)
		}
	}

	return len(remIDs) > 0, nil
}
Exemple #16
0
// FindSSHUser finds an SSH user by public key.
//
// Some parts of the system require that we know not only the SSH key, but also
// the name of the user. That information is stored in etcd.
//
// Params:
// 	- client (EtcdGetter)
// 	- fingerprint (string): The fingerprint of the SSH key.
//
// Returns:
// - username (string)
func FindSSHUser(c cookoo.Context, p *cookoo.Params) (interface{}, cookoo.Interrupt) {
	client := p.Get("client", nil).(Getter)
	fingerprint := p.Get("fingerprint", nil).(string)

	res, err := client.Get("/deis/builder/users", false, true)
	if err != nil {
		log.Warnf(c, "Error querying etcd: %s", err)
		return "", err
	} else if res.Node == nil || !res.Node.Dir {
		log.Warnf(c, "No users found in etcd.")
		return "", errors.New("Users not found")
	}
	for _, user := range res.Node.Nodes {
		log.Infof(c, "Checking user %s", user.Key)
		for _, keyprint := range user.Nodes {
			if strings.HasSuffix(keyprint.Key, fingerprint) {
				parts := strings.Split(user.Key, "/")
				username := parts[len(parts)-1]
				log.Infof(c, "Found user %s for fingerprint %s", username, fingerprint)
				return username, nil
			}
		}
	}

	return "", fmt.Errorf("User not found for fingerprint %s", fingerprint)
}
Exemple #17
0
// VendoredCleanUp is a command that cleans up vendored codebases after an update.
// If enabled (via update) it removed the VCS info from updated vendored
// packages. This should be a suffix to UpdateImports and  VendoredSetup should
// be a prefix to UpdateImports.
func VendoredCleanUp(c cookoo.Context, p *cookoo.Params) (interface{}, cookoo.Interrupt) {
	update := p.Get("update", true).(bool)
	if update != true {
		return false, nil
	}
	cfg := p.Get("conf", nil).(*Config)

	vend, err := VendorPath(c)
	if err != nil {
		return false, err
	}

	for _, dep := range cfg.Imports {
		if dep.UpdateAsVendored == true {
			Info("Cleaning up vendored package %s\n", dep.Name)

			// Remove the VCS directory
			cwd := path.Join(vend, dep.Name)
			repo, err := dep.GetRepo(cwd)
			if err != nil {
				Error("Error cleaning up %s:%s", dep.Name, err)
				continue
			}
			t := repo.Vcs()
			err = os.RemoveAll(cwd + string(os.PathSeparator) + "." + string(t))
			if err != nil {
				Error("Error cleaning up VCS dir for %s:%s", dep.Name, err)
			}
		}

	}

	return true, nil
}
Exemple #18
0
// UpdateReferences updates the revision numbers on all of the imports.
//
// If a `packages` list is supplied, only the given base packages will
// be updated.
//
// Params:
// 	- conf (*yaml.Config): Configuration
// 	- packages ([]string): A list of packages to update. Default is all packages.
func UpdateReferences(c cookoo.Context, p *cookoo.Params) (interface{}, cookoo.Interrupt) {
	cfg := p.Get("conf", &yaml.Config{}).(*yaml.Config)
	plist := p.Get("packages", []string{}).([]string)

	pkgs := list2map(plist)
	restrict := len(pkgs) > 0

	cwd, err := VendorPath(c)
	if err != nil {
		return false, err
	}

	if len(cfg.Imports) == 0 {
		return cfg, nil
	}

	for _, imp := range cfg.Imports {
		if restrict && !pkgs[imp.Name] {
			Debug("===> Skipping %q", imp.Name)
			continue
		}
		commit, err := VcsLastCommit(imp, cwd)
		if err != nil {
			Warn("Could not get commit on %s: %s", imp.Name, err)
		}
		imp.Reference = commit
	}

	return cfg, nil
}
Exemple #19
0
// RunOnce runs the equivalent of `confd --onetime`.
//
// This may run the process repeatedly until either we time out (~20 minutes) or
// the templates are successfully built.
//
// Importantly, this blocks until the run is complete.
//
// Params:
// - node (string): The etcd node to use. (Only etcd is currently supported)
//
// Returns:
// - The []bytes from stdout and stderr when running the program.
//
func RunOnce(c cookoo.Context, p *cookoo.Params) (interface{}, cookoo.Interrupt) {
	node := p.Get("node", defaultEtcd).(string)

	dargs := []string{"-onetime", "-node", node, "-log-level", "error"}

	log.Info(c, "Building confd templates. This may take a moment.")

	limit := 1200
	timeout := time.Second * 3
	var lasterr error
	start := time.Now()
	for i := 0; i < limit; i++ {
		out, err := exec.Command("confd", dargs...).CombinedOutput()
		if err == nil {
			log.Infof(c, "Templates generated for %s on run %d", node, i)
			return out, nil
		}
		log.Debugf(c, "Recoverable error: %s", err)
		log.Debugf(c, "Output: %q", out)
		lasterr = err

		time.Sleep(timeout)
		log.Infof(c, "Re-trying template build. (Elapsed time: %d)", time.Now().Sub(start)/time.Second)
	}

	return nil, fmt.Errorf("Could not build confd templates before timeout. Last error: %s", lasterr)
}
Exemple #20
0
// ReplayHistory sends back the history to a subscriber.
//
// This should be called before the client goes into active listening.
//
// Params:
// - topic (string): The topic to fetch.
//
// Returns:
// 	- int: The number of history messages sent to the client.
func ReplayHistory(c cookoo.Context, p *cookoo.Params) (interface{}, cookoo.Interrupt) {
	req := c.Get("http.Request", nil).(*http.Request)
	res := c.Get("http.ResponseWriter", nil).(ResponseWriterFlusher)
	medium, _ := getMedium(c)
	name := p.Get("topic", "").(string)

	// This does not manage topics. If there is no topic set, we silently fail.
	if len(name) == 0 {
		c.Log("info", "No topic name given to ReplayHistory.")
		return 0, nil
	}
	top, ok := medium.Topic(name)
	if !ok {
		c.Logf("info", "No topic named %s exists yet. No history replayed.", name)
		return 0, nil
	}

	topic, ok := top.(HistoriedTopic)
	if !ok {
		c.Logf("info", "No history for topic %s.", name)
		res.Header().Add(XHistoryEnabled, "False")
		return 0, nil
	}
	res.Header().Add(XHistoryEnabled, "True")

	since := req.Header.Get(XHistorySince)
	max := req.Header.Get(XHistoryLength)

	// maxLen can be used either on its own or paired with X-History-Since.
	maxLen := 0
	if len(max) > 0 {
		m, err := parseHistLen(max)
		if err != nil {
			c.Logf("info", "failed to parse X-History-Length %s", max)
		} else {
			maxLen = m
		}
	}
	if len(since) > 0 {
		ts, err := parseSince(since)
		if err != nil {
			c.Logf("warn", "Failed to parse X-History-Since field %s: %s", since, err)
			return 0, nil
		}
		toSend := topic.Since(ts)

		// If maxLen is also set, we trim the list by sending the newest.
		ls := len(toSend)
		if maxLen > 0 && ls > maxLen {
			offset := ls - maxLen - 1
			toSend = toSend[offset:]
		}
		return sendHistory(c, res, toSend)
	} else if maxLen > 0 {
		toSend := topic.Last(maxLen)
		return sendHistory(c, res, toSend)
	}

	return 0, nil
}
Exemple #21
0
// Expand expands the environment variables in the given string and returns the result.
//
// Params:
// 	- content (string): The given string to expand.
//
// Returns:
//  - The expanded string. This expands against the os environemnt (os.ExpandEnv).
func Expand(c cookoo.Context, p *cookoo.Params) (interface{}, cookoo.Interrupt) {
	s := p.Get("content", "").(string)

	// TODO: We could easily add support here for Expand().

	return os.ExpandEnv(s), nil
}
Exemple #22
0
// GuessDeps tries to get the dependencies for the current directory.
//
// Params
// 	- dirname (string): Directory to use as the base. Default: "."
func GuessDeps(c cookoo.Context, p *cookoo.Params) (interface{}, cookoo.Interrupt) {
	buildContext, err := GetBuildContext()
	if err != nil {
		return nil, err
	}
	base := p.Get("dirname", ".").(string)
	deps := make(map[string]bool)
	err = findDeps(buildContext, deps, base, "")
	deps = compactDeps(deps)
	delete(deps, base)
	if err != nil {
		return nil, err
	}

	config := new(Config)

	// Get the name of the top level package
	config.Name = guessPackageName(buildContext, base)
	config.Imports = make([]*Dependency, len(deps))
	i := 0
	for pa := range deps {
		Info("Found reference to %s\n", pa)
		d := &Dependency{
			Name: pa,
		}
		config.Imports[i] = d
		i++
	}

	return config, nil
}
Exemple #23
0
// BuildImage builds a docker image.
//
// Essentially, this executes:
// 	docker build -t TAG PATH
//
// Params:
// 	- path (string): The path to the image. REQUIRED
// 	- tag (string): The tag to build.
func BuildImage(c cookoo.Context, p *cookoo.Params) (interface{}, cookoo.Interrupt) {
	path := p.Get("path", "").(string)
	tag := p.Get("tag", "").(string)

	log.Infof(c, "Building docker image %s (tag: %s)", path, tag)

	return buildImg(c, path, tag)
}
Exemple #24
0
// Sleep delays the execution of the remainder of the chain of commands.
//
// Params:
// 	-duration (time.Duration): Time to sleep.
//  -message (string): The message to log when entering sleep.
func Sleep(c cookoo.Context, p *cookoo.Params) (interface{}, cookoo.Interrupt) {
	dur := p.Get("duration", 10*time.Millisecond).(time.Duration)
	msg := p.Get("messages", "Sleeping").(string)
	log.Info(c, msg)
	time.Sleep(dur)
	log.Info(c, "Woke up.")
	return true, nil
}
Exemple #25
0
// ReadyToGlide fails if the environment is not sufficient for using glide.
//
// Most importantly, it fails if glide.yaml is not present in the current
// working directory.
func ReadyToGlide(c cookoo.Context, p *cookoo.Params) (interface{}, cookoo.Interrupt) {
	fname := p.Get("filename", "glide.yaml").(string)
	if _, err := os.Stat(fname); err != nil {
		cwd, _ := os.Getwd()
		return false, fmt.Errorf("%s is missing from %s", fname, cwd)
	}
	return true, nil
}
Exemple #26
0
// Package gets a package.
//
// Params:
//	- name (string): Package name
// Returns:
// 	- *model.Package
func Package(c cookoo.Context, p *cookoo.Params) (interface{}, cookoo.Interrupt) {
	name := p.Get("name", "").(string)

	var pkg model.Package
	err := ds(c).C("packages").Find(bson.M{"name": name}).One(&pkg)

	return &pkg, err
}
Exemple #27
0
// VendoredSetup is a command that does the setup for vendored directories.
// If enabled (via update) it marks vendored directories that are being updated
// and removed the old code. This should be a prefix to UpdateImports and
// VendoredCleanUp should be a suffix to UpdateImports.
func VendoredSetup(c cookoo.Context, p *cookoo.Params) (interface{}, cookoo.Interrupt) {
	update := p.Get("update", false).(bool)
	conf := p.Get("conf", nil).(*cfg.Config)

	updatingVendored = update

	return conf, nil
}
Exemple #28
0
// GuardYaml protects the glide yaml file from being overwritten.
func GuardYaml(c cookoo.Context, p *cookoo.Params) (interface{}, cookoo.Interrupt) {
	fname := p.Get("filename", "glide.yaml").(string)
	if _, err := os.Stat(fname); err == nil {
		cwd, _ := os.Getwd()
		return false, fmt.Errorf("Cowardly refusing to overwrite %s in %s", fname, cwd)
	}

	return true, nil
}
Exemple #29
0
// LockFileExists checks if a lock file exists. If not it jumps to the update
// command.
func LockFileExists(c cookoo.Context, p *cookoo.Params) (interface{}, cookoo.Interrupt) {
	fname := p.Get("filename", "glide.lock").(string)
	if _, err := os.Stat(fname); err != nil {
		Info("Lock file (glide.lock) does not exist. Performing update.")
		return false, &cookoo.Reroute{"update"}
	}

	return true, nil
}
Exemple #30
0
// Flush sends content to output.
//
// If no writer is specified, this will attempt to write to whatever is in the
// Context with the key "http.ResponseWriter". If no suitable writer is found, it will
// not write to anything at all.
//
// Params:
// 	- writer: A Writer of some sort. This will try to write to the HTTP response if no writer
// 	is specified.
// 	- content: The content to write as a body. If this is a byte[], it is sent unchanged. Otherwise.
// 	we first try to convert to a string, then pass it into a writer.
// 	- contentType: The content type header (e.g. text/html). Default is text/plain
// 	- responseCode: Integer HTTP Response Code: Default is `http.StatusOK`.
// 	- headers: a map[string]string of HTTP headers. The keys will be run through
// 	 http.CannonicalHeaderKey()
//
// Note that this is optimized for writing from strings or arrays, not Readers. For larger
// objects, you may find it more efficient to use a different command.
//
// Context:
// - If this finds `web.ContentEncoding`, it will set a content-encoding header.
//
// Returns
//
// 	- boolean true
func Flush(cxt cookoo.Context, params *cookoo.Params) (interface{}, cookoo.Interrupt) {

	// Make sure we have a place to write this stuff.
	writer, ok := params.Has("writer")
	if writer == nil {
		writer, ok = cxt.Has("http.ResponseWriter")
		if !ok {
			return false, nil
		}
	}
	out := writer.(http.ResponseWriter)

	// Get the rest of the info.
	code := params.Get("responseCode", http.StatusOK).(int)
	header := out.Header()
	contentType := params.Get("contentType", "text/plain; charset=utf-8").(string)

	// Prepare the content.
	var content []byte
	rawContent, ok := params.Has("content")
	if !ok {
		// No content. Send nothing in the body.
		content = []byte("")
	} else if byteContent, ok := rawContent.([]byte); ok {
		// Got a byte[]; add it as is.
		content = byteContent
	} else {
		// Use the formatter to convert to a string, and then
		// cast it to bytes.
		content = []byte(fmt.Sprintf("%v", rawContent))
	}

	// Add headers:
	header.Set(http.CanonicalHeaderKey("content-type"), contentType)

	te := cxt.Get(ContentEncoding, "").(string)
	if len(te) > 0 {
		header.Set(http.CanonicalHeaderKey("transfer-encoding"), te)
	}

	headerO, ok := params.Has("headers")
	if ok {
		headers := headerO.(map[string]string)
		for k, v := range headers {
			header.Add(http.CanonicalHeaderKey(k), v)
		}
	}

	// Send the headers.
	out.WriteHeader(code)

	//io.WriteString(out, content)
	out.Write(content)

	return true, nil
}