コード例 #1
0
ファイル: gae.go プロジェクト: rainycape/gondola
func gaeDevCommand(_ *command.Args, opts *gaeDevOptions) error {
	log.Debugf("starting App Engine development server - press Control+C to stop")
	var buildArgs []string
	resources, err := makeAppAssets(buildArgs)
	if err != nil {
		return err
	}
	go watchAppResources(buildArgs, resources)
	serveCmd, err := startServe(buildArgs, opts)
	if err != nil {
		return err
	}
	errCh := make(chan error, 1)
	go func() {
		errCh <- serveCmd.Wait()
	}()
	ch := make(chan os.Signal, 1)
	signal.Notify(ch, os.Interrupt)
	select {
	case <-ch:
		log.Debugf("exiting")
		<-errCh
		log.Debugf("exited")
	case err := <-errCh:
		return err
	}
	return nil
}
コード例 #2
0
ファイル: template.go プロジェクト: rainycape/gondola
func (t *Template) replaceExtendTag(name string, treeMap map[string]*parse.Tree, from string) error {
	var err error
	hasExtend := false
	var loc string
	for _, v := range treeMap {
		templateutil.WalkTree(v, func(n, p parse.Node) {
			if err != nil {
				return
			}
			if templateutil.IsPseudoFunction(n, "extend") {
				if hasExtend {
					loc2, _ := v.ErrorContext(n)
					err = fmt.Errorf("multiple {{ extend }} tags in %q, %s and %s", name, loc, loc2)
					return
				}
				hasExtend = true
				loc, _ = v.ErrorContext(n)
				var repl parse.Node
				if from == "" {
					// empty
					log.Debugf("removing {{ extend }} from %q", name)
					repl = &parse.TextNode{
						NodeType: parse.NodeText,
						Pos:      n.Position(),
					}
				} else {
					log.Debugf("extending %q at %s with %q", name, loc, from)
					repl = templateutil.TemplateNode(from, n.Position())
				}
				err = templateutil.ReplaceNode(n, p, repl)
			}
		})
	}
	return err
}
コード例 #3
0
ファイル: client.go プロジェクト: rainycape/governator
func sendCommand(serverAddr string, args []string) (bool, error) {
	scheme, addr, err := parseServerAddr(serverAddr)
	if err != nil {
		return false, err
	}
	conn, err := net.Dial(scheme, addr)
	if err != nil {
		return false, err
	}
	defer conn.Close()
	if err := encodeArgs(conn, args); err != nil {
		return false, err
	}
	log.Debugf("sent command %s", args)
	closed := false
	ch := make(chan os.Signal, 1)
	signal.Notify(ch, os.Interrupt)
	defer signal.Stop(ch)
	done := make(chan struct{}, 1)
	defer func() {
		done <- struct{}{}
	}()
	go func() {
		select {
		case <-ch:
			closed = true
			conn.Close()
		case <-done:
		}
	}()
	ok := true
	for {
		r, s, err := decodeResponse(conn)
		if err != nil {
			if closed {
				return ok, nil
			}
			return ok, err
		}
		log.Debugf("received response %d", r)
		switch r {
		case respEnd:
			return ok, nil
		case respOk:
			fmt.Print(s)
		case respErr:
			ok = false
			fmt.Fprint(os.Stderr, s)
		default:
			return false, fmt.Errorf("invalid response type %d", r)
		}
	}
	return ok, nil
}
コード例 #4
0
ファイル: app.go プロジェクト: rainycape/gondola
func (app *App) importAssets(included *includedApp) error {
	im := included.app.assetsManager
	if !app.shouldImportAssets() {
		im.SetPrefix(included.prefix + im.Prefix())
		return nil
	}
	m := app.assetsManager
	prefix := strings.ToLower(included.name)
	renames := make(map[string]string)
	err := vfs.Walk(im.VFS(), "/", func(fs vfs.VFS, p string, info os.FileInfo, err error) error {
		if err != nil || info.IsDir() {
			return err
		}
		if p != "" && p[0] == '/' {
			p = p[1:]
		}
		log.Debugf("will import asset %v from app %s", p, included.name)
		src, err := im.Load(p)
		if err != nil {
			return err
		}
		defer src.Close()
		seeker, err := assets.Seeker(src)
		if err != nil {
			return err
		}
		sum := hashutil.Fnv32a(seeker)
		nonExt := p[:len(p)-len(path.Ext(p))]
		dest := path.Join(prefix, nonExt+".gen."+sum+path.Ext(p))
		renames[p] = dest
		log.Debugf("importing asset %q as %q", p, dest)
		if m.Has(dest) {
			return nil
		}
		f, err := m.Create(dest, true)
		if err != nil {
			return err
		}
		defer f.Close()
		if _, err := seeker.Seek(0, os.SEEK_SET); err != nil {
			return err
		}
		if _, err := io.Copy(f, seeker); err != nil {
			return err
		}
		return nil
	})
	if err != nil {
		return err
	}
	included.renames = renames
	return nil
}
コード例 #5
0
ファイル: extract.go プロジェクト: rainycape/gondola
func extractGoType(messages messageMap, fset *token.FileSet, f *ast.File, typ string) error {
	// for castings
	calls, err := astutil.Calls(fset, f, typ)
	if err != nil {
		return err
	}
	for _, c := range calls {
		if len(c.Args) > 0 {
			lit, pos := astutil.StringLiteral(fset, c.Args[0])
			if pos == nil {
				p := fset.Position(c.Pos())
				log.Debugf("Skipping cast to %s (%v) - not a literal", typ, p)
				continue
			}
			comment := comments(fset, f, pos)
			if err := messages.AddString(&astutil.String{Value: lit, Position: pos}, comment); err != nil {
				return err
			}
		}
	}
	strings, err := astutil.Strings(fset, f, typ)
	if err != nil {
		return err
	}
	for _, s := range strings {
		comment := comments(fset, f, s.Position)
		if err := messages.AddString(s, comment); err != nil {
			return err
		}
	}
	return nil
}
コード例 #6
0
ファイル: extract.go プロジェクト: rainycape/gondola
func extractGoMessages(messages messageMap, path string, opts *ExtractOptions) error {
	log.Debugf("Extracting messages from Go file %s", path)
	fset := token.NewFileSet()
	f, err := parser.ParseFile(fset, path, nil, parser.ParseComments)
	if err != nil {
		return fmt.Errorf("error parsing go file %s: %s", path, err)
	}
	if opts != nil {
		for _, v := range opts.Functions {
			if v.Template {
				continue
			}
			if err := extractGoFunc(messages, fset, f, v); err != nil {
				return err
			}
		}
		for _, v := range opts.Types {
			if err := extractGoType(messages, fset, f, v); err != nil {
				return err
			}
		}
		for _, v := range opts.TagFields {
			if err := extractGoTagField(messages, fset, f, v); err != nil {
				return err
			}
		}
	}
	return nil
}
コード例 #7
0
ファイル: bake.go プロジェクト: rainycape/gondola
func bakeCommand(_ *command.Args, opts *bakeOptions) error {
	extensions := []string{".html", ".css", ".js"}
	if opts.Dir == "" {
		return errors.New("dir can't be empty")
	}
	if opts.Name == "" {
		base := filepath.Base(opts.Dir)
		if opts.VFS {
			opts.Name = base + "FS"
		} else {
			opts.Name = base + "Data"
		}
	}
	if opts.Out == "" {
		opts.Out = filepath.Base(opts.Dir) + "_baked.go"
	}
	// go ignores files starting with _
	opts.Out = strings.TrimLeft(opts.Out, "_")
	extensions = append(extensions, strings.Split(opts.Extensions, ",")...)
	var buf bytes.Buffer
	odir := filepath.Dir(opts.Out)
	p, err := build.ImportDir(odir, 0)
	if err == nil {
		buf.WriteString(fmt.Sprintf("package %s\n", p.Name))
	}
	buf.WriteString(genutil.AutogenString())
	if err := writeBakedFSCode(&buf, opts, extensions); err != nil {
		return err
	}
	if err := genutil.WriteAutogen(opts.Out, buf.Bytes()); err != nil {
		return err
	}
	log.Debugf("Assets written to %s (%d bytes)", opts.Out, buf.Len())
	return nil
}
コード例 #8
0
ファイル: template.go プロジェクト: rainycape/gondola
func (t *Template) Compile() error {
	if err := t.noCompiled("can't compile"); err != nil {
		return err
	}
	if err := t.preparePlugins(); err != nil {
		return err
	}
	for _, v := range t.referencedTemplates() {
		if _, ok := t.trees[v]; !ok {
			log.Debugf("adding missing template %q as empty", v)
			tree := compileTree("")
			t.AddParseTree(v, tree)
		}
	}
	if err := t.prepareAssets(); err != nil {
		return err
	}
	prog, err := newProgram(t)
	if err != nil {
		return err
	}
	prog.debugDump()
	t.prog = prog
	return nil
}
コード例 #9
0
ファイル: i18n.go プロジェクト: rainycape/gondola
func compileMessagesCommand(_ *command.Args, opts *compileMessagesOptions) error {
	var poFiles []string
	err := filepath.Walk(opts.Messages, func(path string, info os.FileInfo, err error) error {
		if err != nil {
			return err
		}
		if !info.IsDir() && strings.ToLower(filepath.Ext(path)) == ".po" {
			log.Debugf("compiling po file %s", path)
			poFiles = append(poFiles, path)
		}
		return nil
	})
	if err != nil {
		return err
	}
	pos := make([]*po.Po, len(poFiles))
	for ii, v := range poFiles {
		p, err := po.ParseFile(v)
		if err != nil {
			return err
		}
		pos[ii] = p
	}
	copts := &messages.CompileOptions{DefaultContext: opts.Context}
	return messages.Compile(opts.Out, pos, copts)
}
コード例 #10
0
ファイル: gae.go プロジェクト: rainycape/gondola
func makeAppAssets(buildArgs []string) ([]string, error) {
	log.Debugf("compiling app assets")
	if err := runBuild(buildArgs); err != nil {
		return nil, err
	}
	p, err := appPath()
	if err != nil {
		return nil, err
	}
	defer os.Remove(p)
	err = runCmd(exec.Command(p, "-log-debug=false", "make-assets"))
	if err != nil {
		return nil, err
	}
	var buf bytes.Buffer
	cmd := exec.Command(p, "_print-resources")
	cmd.Stdout = &buf
	if err := cmd.Run(); err != nil {
		return nil, err
	}
	var m map[string]string
	if err := json.Unmarshal(buf.Bytes(), &m); err != nil {
		return nil, err
	}
	values := make([]string, 0, len(m))
	for _, v := range m {
		values = append(values, v)
	}
	return values, nil
}
コード例 #11
0
ファイル: packages.go プロジェクト: rainycape/gondola
func updatePackage(e *doc.Environment, pkg string) error {
	if strings.HasSuffix(pkg, "/") {
		pkg += "..."
	}
	goBin := "go"
	env := make(map[string]string)
	for _, v := range os.Environ() {
		if eq := strings.Index(v, "="); eq >= 0 {
			env[v[:eq]] = v[eq+1:]
		}
	}
	if goRoot := e.Context.GOROOT; goRoot != "" {
		goBin = filepath.Join(goRoot, "bin", "go")
		env["GOROOT"] = goRoot
	}
	if goPath := e.Context.GOPATH; goPath != "" {
		env["GOPATH"] = goPath
	}
	cmd := exec.Command(goBin, "get", "-u", "-v", pkg)
	cmdEnv := make([]string, 0, len(env))
	for k, v := range env {
		cmdEnv = append(cmdEnv, k+"="+v)
	}
	cmd.Env = cmdEnv
	log.Debugf("Updating package %s", pkg)
	if log.Level() == log.LDebug {
		cmd.Stdout = os.Stdout
		cmd.Stderr = os.Stderr
	}
	return cmd.Run()
}
コード例 #12
0
ファイル: driver.go プロジェクト: rainycape/gondola
func (d *Driver) Initialize(ms []driver.Model) error {
	// Create tables
	for _, v := range ms {
		tbl, err := d.makeTable(v)
		if err != nil {
			return err
		}
		existingTbl, err := d.backend.Inspect(d.db, v)
		if err != nil {
			return err
		}
		if existingTbl != nil {
			err = d.mergeTable(v, existingTbl, tbl)
		} else {
			if len(tbl.Fields) == 0 {
				log.Debugf("Skipping collection %s (model %v) because it has no fields", v.Table, v)
				continue
			}
			// Table does not exists, create it
			err = d.createTable(v, tbl)
		}
		if err != nil {
			return err
		}
	}
	// Create indexes
	for _, v := range ms {
		if err := d.createIndexes(v); err != nil {
			return err
		}
	}
	return nil
}
コード例 #13
0
ファイル: file_writer.go プロジェクト: rainycape/governator
func (f *fileWriter) Open(name string) error {
	dir, err := os.Stat(f.dir)
	if err != nil || !dir.IsDir() {
		os.Remove(f.dir)
		// Make logs directory
		if err := os.MkdirAll(f.dir, 0755); err != nil {
			return err
		}
	}
	if f.f != nil {
		if err := f.Close(); err != nil {
			return err
		}
	}
	f.name = name
	logPath := f.logPath(0)
	w, err := os.OpenFile(logPath, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)
	if err != nil {
		return fmt.Errorf("error opening log file %s: %s", logPath, err)
	}
	log.Debugf("opened log file %s", name)
	info, err := w.Stat()
	if err != nil {
		w.Close()
		return err
	}
	f.size = uint64(info.Size())
	f.f = w
	return nil
}
コード例 #14
0
ファイル: blobstore.go プロジェクト: rainycape/gondola
// Remove deletes the file with the given id.
func (s *Blobstore) Remove(id string) error {
	s.drv.Remove(s.metaName(id))
	err := s.drv.Remove(id)
	if err == nil {
		log.Debugf("[BLOBSTORE]: Removed %v", id)
	}
	return err
}
コード例 #15
0
ファイル: app.go プロジェクト: rainycape/gondola
func (app *App) handleError(ctx *Context, err interface{}) bool {
	if gerr, ok := err.(Error); ok {
		log.Debugf("HTTP error: %s (%d)", gerr.Error(), gerr.StatusCode())
		app.handleHTTPError(ctx, gerr.Error(), gerr.StatusCode())
		return true
	}
	return false
}
コード例 #16
0
ファイル: server.go プロジェクト: rainycape/governator
func (g *Governator) startServer() error {
	q := newQuit()
	scheme, addr, err := parseServerAddr(g.ServerAddr)
	if err != nil {
		return err
	}
	if scheme == "unix" {
		os.Remove(addr)
	}
	server, err := net.Listen(scheme, addr)
	if err != nil {
		return err
	}
	if scheme == "unix" {
		if gid := getGroupId(AppName); gid >= 0 {
			os.Chown(addr, 0, gid)
			os.Chmod(addr, 0775)
		}
	}
	conns := make(chan net.Conn, 10)
	go func() {
		for {
			conn, err := server.Accept()
			if err != nil {
				log.Errorf("error accepting connection: %s", err)
			}
			log.Debugf("new connection %s", conn.RemoteAddr())
			conns <- conn
		}
	}()
	go func() {
		for {
			select {
			case <-q.stop:
				if scheme == "unix" {
					os.Remove(addr)
				}
				q.sendStopped()
				return
			case conn := <-conns:
				go func() {
					if err := g.serveConn(conn); err != nil {
						log.Errorf("error serving connection: %s", err)
					}
				}()
			}
		}
	}()
	g.mu.Lock()
	defer g.mu.Unlock()
	g.quits = append(g.quits, q)
	return nil
}
コード例 #17
0
ファイル: file_writer.go プロジェクト: rainycape/governator
func (f *fileWriter) rotate() error {
	if err := f.Close(); err != nil {
		return err
	}
	last := []string{f.logPath(f.count - 1), f.compressedLogPath(f.count - 1)}
	for _, v := range last {
		if fileExists(v) {
			log.Debugf("removing %s", v)
			if err := os.Remove(v); err != nil {
				return err
			}
		}
	}
	var compress []string
	for ii := f.count - 2; ii >= 0; ii-- {
		ccur := f.compressedLogPath(ii)
		if fileExists(ccur) {
			to := f.compressedLogPath(ii + 1)
			log.Debugf("moving %s to %s", ccur, to)
			if err := os.Rename(ccur, to); err != nil {
				return err
			}
			continue
		}
		cur := f.logPath(ii)
		if fileExists(cur) {
			to := f.logPath(ii + 1)
			log.Debugf("moving %s to %s", cur, to)
			if err := os.Rename(cur, to); err != nil {
				return err
			}
			compress = append(compress, to)
		}
	}
	for _, v := range compress {
		f.compressFile(v)
	}
	return f.Open(f.name)
}
コード例 #18
0
ファイル: compiler.go プロジェクト: rainycape/gondola
func Compile(m *Manager, name string, typ Type, opts Options) (string, error) {
	ext := path.Ext(name)
	compiler := compilers[typ][strings.ToLower(ext)]
	if compiler == nil {
		return name, nil
	}
	f, err := m.Load(name)
	if err != nil {
		return "", err
	}
	defer f.Close()
	seeker, err := Seeker(f)
	fnv := hashutil.Fnv32a(seeker)
	out := fmt.Sprintf("%s.gen.%s.%s", name, fnv, typ.Ext())
	if o, _ := m.Load(out); o != nil {
		o.Close()
		log.Debugf("%s already compiled to %s", name, out)
		return out, nil
	}
	seeker.Seek(0, 0)
	var buf bytes.Buffer
	log.Debugf("compiling %s to %s", name, out)
	if err := compiler.Compile(&buf, seeker, opts); err != nil {
		return "", err
	}
	w, err := m.Create(out, true)
	if err != nil {
		return "", err
	}
	if _, err := io.Copy(w, bytes.NewReader(buf.Bytes())); err != nil {
		w.Close()
		return "", err
	}
	if err := w.Close(); err != nil {
		return "", err
	}
	return out, nil
}
コード例 #19
0
ファイル: script.go プロジェクト: rainycape/gondola
func appendScriptFallback(m *Manager, script *Asset, assets *[]*Asset, fallback string) error {
	if fallback != "" {
		if _, ok := script.Attributes["async"]; ok {
			log.Debugf("skipping fallback for async script %s", script.Name)
			return nil
		}
		fb, err := scriptFallback(m, script, fallback)
		if err != nil {
			return err
		}
		*assets = append(*assets, fb)
	}
	return nil
}
コード例 #20
0
ファイル: file_writer.go プロジェクト: rainycape/governator
func (f *fileWriter) compressFile(name string) {
	log.Debugf("will compress %s", name)
	var wg sync.WaitGroup
	wg.Add(1)
	go func() {
		if err := compressFile(name); err != nil {
			log.Errorf("error compressing %s: %s", name, err)
		}
		wg.Done()
	}()
	if f.waitCompress {
		wg.Wait()
	}
}
コード例 #21
0
ファイル: app.go プロジェクト: rainycape/gondola
func (app *App) chainTemplate(t *Template, included *includedApp) (*Template, error) {
	log.Debugf("chaining template %s", t.tmpl.Name())
	container, name, err := app.loadContainerTemplate(included)
	if err != nil {
		return nil, err
	}
	if err := app.rewriteAssets(t.tmpl, included); err != nil {
		return nil, err
	}
	if err := container.tmpl.InsertTemplate(t.tmpl, name); err != nil {
		return nil, err
	}
	return container, nil
}
コード例 #22
0
ファイル: service.go プロジェクト: rainycape/governator
func (s *Service) updateConfig(cfg *Config) {
	if reflect.DeepEqual(s.Config, cfg) {
		// there were changes to the file which don't affect the conf
		return
	}
	log.Debugf("changed service %s's configuration", s.Name())
	start := false
	if s.State == StateStarted {
		start = s.Stop() == nil
	}
	s.Config = cfg
	if start {
		s.Start()
	}
}
コード例 #23
0
ファイル: handlers.go プロジェクト: rainycape/gondola
func ArticleHandler(ctx *app.Context) {
	slug := ctx.IndexValue(0)
	var art *article.Article
	articles := getArticles(ctx)
	for _, v := range articles {
		if v.Slug() == slug {
			art = v
			break
		}
	}
	if art == nil {
		for _, v := range articles {
			for _, s := range v.AllSlugs() {
				if s == slug {
					ctx.MustRedirectReverse(true, ctx.HandlerName(), s)
					return
				}
			}
		}
		ctx.NotFound("article not found")
		return
	}
	fs := vfs.Memory()
	filename := path.Base(art.Filename)
	if filename == "" {
		filename = "article.html"
	}
	if err := vfs.WriteFile(fs, filename, art.Text, 0644); err != nil {
		panic(err)
	}
	log.Debugf("loading article %s", articleId(art))
	tmpl, err := app.LoadTemplate(ctx.App(), fs, nil, filename)
	if err != nil {
		panic(err)
	}
	var buf bytes.Buffer
	if err := tmpl.ExecuteTo(&buf, ctx, nil); err != nil {
		panic(err)
	}
	body := buf.String()
	data := map[string]interface{}{
		"Article": art,
		"Title":   art.Title(),
		"Body":    template.HTML(body),
	}
	ctx.MustExecute("article.html", data)
}
コード例 #24
0
ファイル: app.go プロジェクト: rainycape/gondola
// LoadTemplate loads a template using the template
// loader and the asset manager assocciated with
// this app
func (app *App) LoadTemplate(name string) (*Template, error) {
	app.templatesMutex.RLock()
	tmpl := app.templatesCache[name]
	app.templatesMutex.RUnlock()
	if tmpl == nil {
		var err error
		log.Debugf("Loading root template %s", name)
		if profile.On && profile.Profiling() {
			defer profile.Start("template").Note("load", name).End()
		}
		tmpl, err = app.loadTemplate(app.templatesFS, app.assetsManager, name)
		if err != nil {
			return nil, err
		}
		var funcs []*template.Func
		for _, v := range app.included {
			funcs = append(funcs, &template.Func{
				Name:   v.assetFuncName(),
				Fn:     v.assetFunc(tmpl.tmpl),
				Traits: template.FuncTraitPure,
			})
		}
		tmpl.tmpl.Funcs(funcs)
		for _, v := range app.templatePlugins {
			if err := tmpl.tmpl.AddPlugin(v); err != nil {
				return nil, fmt.Errorf("error adding plugin %q: %s", v.Template.Root(), err)
			}
		}
		if profile.On {
			if profilePlugin != nil {
				tmpl.tmpl.AddPlugin(profilePlugin)
			}
		}
		if err := tmpl.prepare(); err != nil {
			return nil, err
		}
		if !app.cfg.TemplateDebug {
			app.templatesMutex.Lock()
			if app.templatesCache == nil {
				app.templatesCache = make(map[string]*Template)
			}
			app.templatesCache[name] = tmpl
			app.templatesMutex.Unlock()
		}
	}
	return tmpl, nil
}
コード例 #25
0
ファイル: vfsutil.go プロジェクト: rainycape/gondola
// Bake writes the data for a VFS generated from dir to the given
// io.Writer. The extensions argument can be used to limit the
// files included in the VFS by their extension. If empty, all
// files are included.
func Bake(w io.Writer, dir string, extensions []string) error {
	fs, err := vfs.FS(dir)
	if err != nil {
		return err
	}
	if len(extensions) > 0 {
		// Clone the fs and remove files not matching the extension
		exts := make(map[string]bool)
		for _, v := range extensions {
			if v == "" {
				continue
			}
			if v[0] != '.' {
				v = "." + v
			}
			exts[strings.ToLower(v)] = true
		}
		mem := vfs.Memory()
		if err := vfs.Clone(mem, fs); err != nil {
			return err
		}
		err := vfs.Walk(mem, "/", func(fs vfs.VFS, p string, info os.FileInfo, err error) error {
			if err != nil || info.IsDir() {
				return err
			}
			if !exts[strings.ToLower(path.Ext(p))] {
				if err := fs.Remove(p); err != nil {
					return err
				}
			}
			return nil
		})
		if err != nil {
			return err
		}
		fs = mem
	}
	vfs.Walk(fs, "/", func(_ vfs.VFS, p string, info os.FileInfo, err error) error {
		if !info.IsDir() {
			log.Debugf("baking %s", p)
		}
		return nil
	})
	return vfs.WriteTarGzip(w, fs)
}
コード例 #26
0
ファイル: script.go プロジェクト: rainycape/gondola
// Create a local fallback for the given script, downloading it if
// necessary
func scriptFallback(m *Manager, script *Asset, fallback string) (*Asset, error) {
	fallbackName := script.Name
	if !m.Has(fallbackName) {
		var scriptURL string
		if urlutil.IsURL(fallbackName) {
			scriptURL = fallbackName
			fallbackName = "asset.gen." + hashutil.Adler32(fallbackName) + "." + path.Base(fallbackName)
		} else {
			cdn, _, err := Cdn(fallbackName)
			if err != nil {
				return nil, err
			}
			scriptURL = cdn
		}
		if !m.Has(fallbackName) {
			u, err := url.Parse(scriptURL)
			if err != nil {
				return nil, err
			}
			if u.Scheme == "" {
				u.Scheme = "http"
			}
			log.Debugf("fetching local fallback for %s to %s", u, fallbackName)
			resp, err := http.Get(u.String())
			if err != nil {
				return nil, err
			}
			defer resp.Body.Close()
			w, err := m.Create(fallbackName, true)
			if err != nil {
				return nil, err
			}
			defer w.Close()
			if _, err := io.Copy(w, resp.Body); err != nil {
				return nil, err
			}
		}
	}
	return &Asset{
		Name:     fallbackName,
		Position: Bottom,
		Type:     TypeOther,
		HTML:     fmt.Sprintf("<script>%s || document.write('<scr'+'ipt src=\"%s\"><\\/scr'+'ipt>')</script>", fallback, m.URL(fallbackName)),
	}, nil
}
コード例 #27
0
ファイル: blobstore.go プロジェクト: rainycape/gondola
// CreateId works like Create, but uses the given id rather than generating
// a new one. If a file with the same id already exists, it's overwritten.
func (s *Blobstore) CreateId(id string) (*WFile, error) {
	if strings.HasSuffix(id, metaSuffix) {
		return nil, fmt.Errorf("invalid id %s, can't end with .meta", id)
	}
	if len(id) < minIdLength {
		return nil, fmt.Errorf("id is too short (%d characters), minimum length is %d", len(id), minIdLength)
	}
	w, err := s.drv.Create(id)
	if err != nil {
		return nil, err
	}
	log.Debugf("[BLOBSTORE]: Created %v", id)
	return &WFile{
		id:       id,
		file:     w,
		dataHash: newHash(),
		store:    s,
	}, nil
}
コード例 #28
0
ファイル: signals.go プロジェクト: rainycape/gondola
// Emit emits this signal, calling all registered listeners. Note
// that this function should only be called from a typed Signal
// wrapping it. See the package documentation for examples.
func (s *Signal) Emit(data interface{}) {
	s.mu.RLock()
	if c := len(s.listeners); c > 0 {
		listeners := make([]*listener, len(s.listeners))
		copy(listeners, s.listeners)
		// Don't hold the lock while invoking the
		// listeners, otherwise calling Remove()
		// from a handler would cause a deadlock.
		s.mu.RUnlock()
		if s.name != "" {
			log.Debugf("emitting signal %v (%d listeners)", s.name, c)
		}
		for _, v := range listeners {
			v.Handler(data)
		}
	} else {
		s.mu.RUnlock()
	}
}
コード例 #29
0
ファイル: governator.go プロジェクト: rainycape/governator
func (g *Governator) Run() error {
	g.mu.Lock()
	if g.quit != nil {
		g.mu.Unlock()
		return errors.New("governator already running")
	}
	g.quit = newQuit()
	g.mu.Unlock()
	go g.monitor.Run()
	if g.configDir != "" {
		if err := g.startWatching(); err != nil {
			log.Errorf("error watching %s, configuration won't be automatically updated: %s", g.servicesDir(), err)
		}
	}
	if g.ServerAddr != "" {
		if err := g.startServer(); err != nil {
			log.Errorf("error starting server, can't receive remote commands: %s", err)
		}
	}
	g.startServices(nil)
	g.quit.waitForStop()
	g.mu.Lock()
	for _, q := range g.quits {
		q.sendStop()
	}
	// Wait for goroutines to exit cleanly
	for _, q := range g.quits {
		q.waitForStopped()
	}
	g.quits = nil
	g.mu.Unlock()
	// Release the lock for stopServices
	g.stopServices(nil)
	g.mu.Lock()
	defer g.mu.Unlock()
	g.monitor.quit.sendStop()
	g.monitor.quit.waitForStopped()
	log.Debugf("daemon exiting")
	g.quit.sendStopped()
	g.quit = nil
	return nil
}
コード例 #30
0
ファイル: file_writer.go プロジェクト: rainycape/governator
func compressFile(name string) error {
	r, err := os.Open(name)
	if err != nil {
		return err
	}
	defer r.Close()
	w, err := os.OpenFile(name+".gz", os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0644)
	if err != nil {
		return err
	}
	defer w.Close()
	gw := gzip.NewWriter(w)
	defer gw.Close()
	if _, err := io.Copy(gw, r); err != nil {
		return err
	}
	os.Remove(name)
	log.Debugf("compressed %s to %s", r.Name(), w.Name())
	return nil
}