// A build stage creates a new build and adds all the files coming through the channel to
// the Build and returns the result of Build as a File on the output channel.
func Build(c *slurp.C, config Config) slurp.Stage {
	return func(in <-chan slurp.File, out chan<- slurp.File) {

		b := cache{config, make(map[string]*bytes.Buffer)}

		for file := range in {
			path, _ := filepath.Rel(file.Dir, file.Path)
			path = filepath.ToSlash(path)
			c.Infof("Adding %s", path)
			buff := new(bytes.Buffer)
			_, err := buff.ReadFrom(file)
			if err != nil {
				c.Error(err)
			}
			b.Files[path] = buff
			file.Close() //Close files AFTER we have build our package.
		}

		buff := new(bytes.Buffer)
		err := cacheTemplate.Execute(buff, b)
		if err != nil {
			c.Error(err)
			return
		}

		sf := slurp.File{
			Reader: buff,
			Path:   b.Name,
		}
		sf.FileInfo.SetName(b.Name)
		sf.FileInfo.SetSize(int64(buff.Len()))

		out <- sf
	}
}
Beispiel #2
0
// Concatenates all the files from the input channel
// and passes them to output channel with the given name.
func Concat(c *slurp.C, name string) slurp.Stage {
	return func(files <-chan slurp.File, out chan<- slurp.File) {

		var (
			size    int64
			bigfile = new(bytes.Buffer)
		)

		for f := range files {
			c.Infof("Adding %s to %s", f.Path, name)
			n, err := bigfile.ReadFrom(f)
			if err != nil {
				c.Error(err)
				return
			}
			bigfile.WriteRune('\n')
			size += n + 1

			f.Close()
		}

		fi := slurp.FileInfo{}
		fi.SetSize(size)
		fi.SetName(name)

		out <- slurp.File{
			Reader:   bigfile,
			Dir:      "",
			Path:     name,
			FileInfo: fi,
		}
	}
}
Beispiel #3
0
//For The Glory of Debugging.
func List(c *slurp.C) slurp.Stage {
	return func(files <-chan slurp.File, out chan<- slurp.File) {
		for f := range files {
			s, err := f.Stat()
			if err != nil {
				c.Error("Can't get File Stat name.")
			} else {
				c.Infof("slurp.File: %+v Name: %s", f, s.Name())
			}
			out <- f
		}
	}
}
Beispiel #4
0
//Filters out files based on a pattern, if they match,
// they will be closed, otherwise sent to the output channel.
func Filter(c *slurp.C, pattern string) slurp.Stage {
	return FilterFunc(c, func(f slurp.File) bool {
		s, err := f.Stat()
		if err != nil {
			c.Errorf("Can't get File Stat: %s", err.Error())
			return false
		}
		m, err := glob.Match(pattern, s.Name())
		if err != nil {
			c.Error(err)
		}
		return m
	})
}
Beispiel #5
0
func Compile(c *slurp.C) slurp.Stage {

	return func(in <-chan slurp.File, out chan<- slurp.File) {

		var wg sync.WaitGroup
		defer wg.Wait()

		for file := range in {

			// Skip underscored files like Ruby sass
			if string(filepath.Base(file.Path)[0]) == "_" {
				continue
			}

			wg.Add(1)
			go func(file slurp.File) {

				defer wg.Done()

				ctx := gosass.FileContext{
					Options: gosass.Options{
						OutputStyle:  gosass.COMPRESSED_STYLE,
						IncludePaths: make([]string, 0),
					},
					InputPath:    file.Path,
					OutputString: "",
					ErrorStatus:  0,
					ErrorMessage: "",
				}

				gosass.CompileFile(&ctx)

				if ctx.ErrorStatus != 0 {
					c.Error("Sass error: ", ctx.ErrorMessage)
					return
				}

				buf := bytes.NewBufferString(ctx.OutputString)

				file.Reader = buf
				file.FileInfo.SetSize(int64(buf.Len()))

				out <- file

			}(file)
		}
	}
}
Beispiel #6
0
// Copy the file content
func Copy(c *slurp.C, keepath bool) slurp.Stage {
	return func(in <-chan slurp.File, out chan<- slurp.File) {

		fs := []*File{}

		var wg sync.WaitGroup
		defer wg.Wait() //Wait before all templates are executed.

		for file := range in {
			buf := new(bytes.Buffer)
			_, err := buf.ReadFrom(file.Reader)
			file.Close()
			if err != nil {
				c.Error(err)
				continue
			}

			s, err := file.Stat()
			if err != nil {
				c.Error(err)
				break
			}
			name := s.Name()
			file.Dir = ""

			if keepath {
				name = strings.Join(strings.Split(file.Path, "/")[1:], "/")
				file.Dir = strings.Split(file.Dir, "/")[0]
			}
			f := NewFile(name, file.Dir, buf.Bytes())

			fs = append(fs, f)

			file.Path = name
			file.Reader = buf
			file.FileInfo.SetSize(int64(buf.Len()))

			out <- file
		}
	}
}
Beispiel #7
0
// Unzip the zip files from input channel and pass the result
// to the output channel.
func Unzip(c *slurp.C) slurp.Stage {
	return func(in <-chan slurp.File, out chan<- slurp.File) {

		var wg sync.WaitGroup
		for file := range in {

			wg.Add(1)
			go func(file slurp.File) {
				defer wg.Done()

				raw, err := ioutil.ReadAll(file)
				file.Close()

				r, err := zip.NewReader(bytes.NewReader(raw), int64(len(raw)))
				if err != nil {
					c.Error(err)
					return
				}

				counter := c.Counter("unzipping", len(r.File))

				// Iterate through the files in the archive,
				for i, f := range r.File {
					counter.Set(i+1, f.Name)

					content, err := f.Open()
					if err != nil {
					}
					fs := slurp.File{Reader: content, Dir: "", Path: f.Name, FileInfo: slurp.FileInfoFrom(f.FileInfo())}

					out <- fs

				}
			}(file)

		}
		wg.Wait()
	}
}
Beispiel #8
0
// Dest writes the files from the input channel to the dst folder and closes the files.
// It never returns Files.
func Dest(c *slurp.C, dst string) slurp.Stage {
	return func(files <-chan slurp.File, out chan<- slurp.File) {

		var wg sync.WaitGroup
		defer wg.Wait()

		for file := range files {

			realpath, _ := filepath.Rel(file.Dir, file.Path)
			path := filepath.Join(dst, filepath.Dir(realpath))
			err := os.MkdirAll(path, 0700)
			if err != nil {
				c.Error(err)
				return
			}

			if !file.FileInfo.IsDir() {

				wg.Add(1)
				go func(file slurp.File) {

					defer wg.Done()
					defer file.Close()

					realfile, err := os.Create(filepath.Join(dst, realpath))
					if err != nil {
						c.Error(err)
						return
					}
					io.Copy(realfile, file)
					realfile.Close()

				}(file)
			}
		}

	}
}
Beispiel #9
0
// bin is the binary name, it will be passed to os/exec.Command, so the same
// path rules applies.
// the args are the argumetns passed to the program.
func Run(c *slurp.C, bin string, args ...string) slurp.Stage {
	return func(in <-chan slurp.File, out chan<- slurp.File) {

		var wg sync.WaitGroup
		defer wg.Wait()

		for file := range in {

			cmd := exec.Command(bin, args...)
			cmd.Stderr = os.Stderr //TODO: io.Writer logger.

			cmd.Stdin = file.Reader
			content, err := cmd.StdoutPipe()
			if err != nil {
				c.Error(err)
				return
			}

			err = cmd.Start()
			if err != nil {
				c.Error(err)
				return
			}

			wg.Add(1)
			go func(cmd *exec.Cmd) {
				defer wg.Done()
				defer slurp.Close(content)
				cmd.Wait()
			}(cmd)

			file.Reader = content
			out <- file

		}

	}
}
Beispiel #10
0
//Src returns a channel of slurp.Files that match the provided pattern.
func Src(c *slurp.C, globs ...string) slurp.Pipe {

	pipe := make(chan slurp.File)

	files, err := glob.Glob(globs...)

	if err != nil {
		c.Error(err)
		close(pipe)
	}

	cwd, err := os.Getwd()
	if err != nil {
		c.Error(err)
		close(pipe)
		return pipe
	}

	//TODO: Parse globs here, check for invalid globs, split them into "filters".
	go func() {
		defer close(pipe)

		for matchpair := range files {

			f, err := Read(matchpair.Name)
			if err != nil {
				c.Error(err)
				continue
			}

			f.Cwd = cwd
			f.Dir = glob.Dir(matchpair.Glob)
			pipe <- *f
		}

	}()

	return pipe
}