func main() { cmdline.Go(func() error { var bps basePathSlice srcCssFile := flag.String("i", "", "Input css file") dstCssFile := flag.String("o", "", "Output css file, can be the same as input css file") flag.Var(&bps, "base", "Base directory to resolve image files. Default to input css file directory. Can be specified multiple times, it is useful if the input css file is created by tools such as scss from multiple .css files in different directories.") flag.Parse() var ( css []byte out string err error ) if *srcCssFile == "" || *dstCssFile == "" { flag.Usage() return cmdline.NewExitError(2) } if len(bps) == 0 { bps = basePathSlice{filepath.Dir(*srcCssFile)} } if css, err = ioutil.ReadFile(*srcCssFile); err != nil { return errors.NewInput(err) } spriter := sprite.New(string(css), sprite.NewFileService(([]string)(bps), filepath.Dir(*dstCssFile))) if out, err = spriter.Gen(); err != nil { return err } if err = ioutil.WriteFile(*dstCssFile, ([]byte)(out), 0); err != nil { return errors.NewRuntime(err) } return nil }) }
// Do the generation, return translated css file content. Generated sprite // image files are saved using Service interface. func (s *Spriter) Gen() (css string, err error) { var tks []*scanner.Token tks, err = scan(s.css) if err != nil { return } needTranslate := false groups := make(map[string][]*cssImage) for _, tk := range tks { switch tk.Type { case scanner.TokenIdent: needTranslate = tk.Value == "background" case scanner.TokenURI: if needTranslate { var ( st *cssImage g string ) if st, g, err = s.parseCssImage(tk); err != nil { return } if st != nil { groups[g] = append(groups[g], st) } } } } for _, sts := range groups { size := getSpriteSize(sts) var sprite = image.NewRGBA(image.Rectangle{Min: image.Point{}, Max: size}) for _, st := range sts { b := st.img.bounds() draw.Draw(sprite, b.Add(image.Pt(-st.img.sp.X, st.img.sp.Y)), st.img.img, b.Min, draw.Src) } hash := md5.New() buf := &bytes.Buffer{} w := io.MultiWriter(buf, hash) if err = png.Encode(w, sprite); err != nil { err = errors.NewRuntime(err) return } token := base64.URLEncoding.EncodeToString(hash.Sum(nil)[:6]) var f io.Writer f, err = s.sv.CreateSpriteImage(token + ".png") if err != nil { return } defer closeClosable(f) if _, err = f.Write(buf.Bytes()); err != nil { return } for _, st := range sts { st.tk.Value = "url(" + token + ".png) no-repeat" if st.img.sp.X != 0 { st.tk.Value += fmt.Sprintf(" %dpx 0", st.img.sp.X) } } } return writer.Dumps(tks) }
Ω(e.Error()).Should(Equal(msg)) Ω(e.CausedBy()).Should(Equal(causedBy)) } Context("Wrap error", func() { It("New", func() { assertError(errors.New("foo"), "foo", errors.ByBug) }) It("NewBug", func() { assertError(errors.NewBug(syserr.New("foo")), "foo", errors.ByBug) }) It("NewRuntime", func() { assertError(errors.NewRuntime(syserr.New("foo")), "foo", errors.ByRuntime) }) It("NewExternal", func() { assertError(errors.NewExternal(syserr.New("foo")), "foo", errors.ByExternal) }) It("NewInput", func() { assertError(errors.NewInput(syserr.New("foo")), "foo", errors.ByInput) }) Context("Not wrap nil", func() { It("NewBug", func() { Ω(errors.NewBug(nil)).Should(BeNil()) })