Exemplo n.º 1
0
func (p *Project) startLocked() error {
	p.port = randomFreePort()
	cmd := p.ProjectCmd()
	log.Infof("Starting %s (%s)", p.Name(), cmdString(cmd))
	p.cmd = cmd
	p.out.Reset()
	p.runError = nil
	p.exitCode = 0
	err := cmd.Start()
	go func() {
		werr := cmd.Wait()
		if cmd == p.cmd {
			// Othewise the process was intentionally killed
			if s := cmd.ProcessState; s != nil {
				exitCode := exitStatus(s)
				p.Lock()
				defer p.Unlock()
				p.runError = werr
				p.exitCode = exitCode
				log.Warningf("%s exited with code %d", p.Name(), exitCode)
			}
		}
	}()
	time.AfterFunc(100*time.Millisecond, p.projectStarted)
	return err
}
Exemplo n.º 2
0
// Timings returns the available timings for the current
// goroutine. Note that calling Timings will end any events
// which have been set to automatically end (with Timed.AutoEnd)
// so this function should only be called at the end of the
// request lifecycle.
func Timings() []*Timing {
	var timings map[string]*Timing
	contexts.RLock()
	ctx := contexts.data[goroutineId()]
	if ctx != nil {
		timings = make(map[string]*Timing)
		ctx.Lock()
		for _, v := range ctx.events {
			if v.ended.IsZero() {
				if v.autoend {
					v.End()
				} else {
					if len(v.notes) > 0 {
						log.Warningf("unfinished %q event (%s)", v.name, v.notes)
					} else {
						log.Warningf("unfinished %q event", v.name)
					}
					continue
				}
			}
			timing := timings[v.name]
			if timing == nil {
				timing = &Timing{Name: v.name}
				timings[v.name] = timing
			}
			timing.Events = append(timing.Events, &Event{v.started, v.ended, v.notes})
		}
		ctx.Unlock()
	}
	contexts.RUnlock()
	ret := make([]*Timing, 0, len(timings))
	for _, v := range timings {
		ret = append(ret, v)
	}
	return ret
}
Exemplo n.º 3
0
// Handler returns an http.handlerFunc which serves the assets from this
// Manager. To avoid circular imports, this function returns an http.HandlerFunc
// rather than a gnd.la/app.Handler. To obtain a gnd.la/app.Handler use
// gnd.la/app.HandlerFromHTTPFunc.
func (m *Manager) Handler() http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		p := m.Path(r.URL)
		f, err := m.Load(p)
		if err != nil {
			log.Warningf("error serving %s: %s", r.URL, err)
			return
		}
		seeker, err := Seeker(f)
		if err != nil {
			log.Warningf("error serving %s: %s", r.URL, err)
			return
		}
		var modtime time.Time
		if st, err := m.VFS().Stat(p); err == nil {
			modtime = st.ModTime()
		}
		if r.URL.RawQuery != "" {
			httpserve.NeverExpires(w)
		}
		http.ServeContent(w, r, r.URL.Path, modtime, seeker)
		f.Close()
	}
}
Exemplo n.º 4
0
func (t *Template) prepareAssets() error {
	groups, err := t.preparedAssetsGroups(t.vars, t, nil)
	if err != nil {
		return err
	}
	if err := sortGroups(groups); err != nil {
		return err
	}
	var top bytes.Buffer
	var bottom bytes.Buffer
	for _, group := range groups {
		// Only bundle and use CDNs in non-debug mode
		if !t.Debug {
			if group[0].Options.Bundle() || group[0].Options.Bundable() {
				bundled, err := assets.Bundle(group, group[0].Options)
				if err == nil {
					group = []*assets.Group{
						&assets.Group{
							Manager: group[0].Manager,
							Assets:  []*assets.Asset{bundled},
							Options: group[0].Options,
						},
					}
				} else {
					var names []string
					for _, g := range group {
						for _, a := range g.Assets {
							names = append(names, a.Name)
						}
					}
					log.Errorf("error bundling assets %s: %s - using individual assets", names, err)
				}
			} else if group[0].Options.Cdn() {
				for _, g := range group {
					var groupAssets []*assets.Asset
					for _, a := range g.Assets {
						cdnAssets, err := assets.CdnAssets(g.Manager, a)
						if err != nil {
							if !g.Manager.Has(a.Name) {
								return fmt.Errorf("could not find CDN for asset %q: %s", a.Name, err)
							}
							log.Warningf("could not find CDN for asset %q: %s - using local copy", a.Name, err)
							groupAssets = append(groupAssets, a)
							continue
						}
						groupAssets = append(groupAssets, cdnAssets...)
					}
					g.Assets = groupAssets
				}
			}
		}
		for _, g := range group {
			for _, v := range g.Assets {
				switch v.Position {
				case assets.Top:
					if err := assets.RenderTo(&top, g.Manager, v); err != nil {
						return fmt.Errorf("error rendering asset %q", v.Name)
					}
					top.WriteByte('\n')
				case assets.Bottom:
					if err := assets.RenderTo(&bottom, g.Manager, v); err != nil {
						return fmt.Errorf("error rendering asset %q", v.Name)
					}
					bottom.WriteByte('\n')
				default:
					return fmt.Errorf("asset %q has invalid position %s", v.Name, v.Position)
				}
			}
		}
	}
	t.topAssets = top.Bytes()
	t.bottomAssets = bottom.Bytes()
	return nil
}
Exemplo n.º 5
0
func Bundle(groups []*Group, opts Options) (*Asset, error) {
	assetType := Type(-1)
	var names []string
	for _, group := range groups {
		for _, v := range group.Assets {
			if v.Type == TypeOther {
				return nil, fmt.Errorf("asset %q does not specify a Type and can't be bundled", v.Name)
			}
			if assetType < 0 {
				assetType = v.Type
			} else if assetType != v.Type {
				return nil, fmt.Errorf("asset %q has different code type %s (first asset is of type %s)", v.Name, v.Type, assetType)
			}
			names = append(names, v.Name)
		}
	}
	bundler := bundlers[assetType]
	if bundler == nil {
		return nil, fmt.Errorf("no bundler for %s", assetType)
	}
	// Prepare the code, changing relative paths if required
	name, err := bundleName(groups, assetType.Ext(), opts)
	if err != nil {
		return nil, err
	}
	// The bundle is output to the first manager
	m := groups[0].Manager
	// Check if the code has been already bundled
	if m.Has(name) {
		log.Debugf("%s already bundled into %s and up to date", names, name)
	} else {
		dir := path.Dir(name)
		log.Debugf("bundling %v", names)
		var code []string
		for _, group := range groups {
			for _, v := range group.Assets {
				c, err := v.Code(group.Manager)
				if err != nil {
					return nil, fmt.Errorf("error getting code for asset %q: %s", v.Name, err)
				}
				if vd := path.Dir(v.Name); vd != dir {
					if assetType == TypeCSS {
						log.Debugf("asset %q will move from %v to %v, rewriting relative paths...", v.Name, vd, dir)
						c = replaceRelativePaths(c, vd, dir)
					} else {
						log.Warningf("asset %q will move from %v to %v, relative paths might not work", v.Name, vd, dir)
					}
				}
				code = append(code, c)
			}
		}
		// Bundle to a buf first. We don't want to create
		// the file if the bundling fails.
		var buf bytes.Buffer
		allCode := strings.Join(code, "\n\n")
		reader := strings.NewReader(allCode)
		if err := bundler.Bundle(&buf, reader, opts); err != nil {
			return nil, err
		}
		s := makeLinksCacheable(m, dir, buf.Bytes())
		initial := len(allCode)
		final := len(s)
		var percent float64
		if initial != 0 {
			percent = float64(final) / float64(initial) * 100
		}
		log.Debugf("reduced size from %s to %s (%.2f%%)", formatutil.Size(uint64(initial)),
			formatutil.Size(uint64(final)), percent)
		w, err := m.Create(name, true)
		if err == nil {
			if _, err := io.Copy(w, strings.NewReader(s)); err != nil {
				w.Close()
				return nil, err
			}
			if err := w.Close(); err != nil {
				return nil, err
			}
		} else {
			// If the file exists, is up to date
			if !os.IsExist(err) {
				return nil, err
			}
		}
	}
	return &Asset{
		Name:       name,
		Type:       assetType,
		Attributes: groups[0].Assets[0].Attributes,
		Position:   groups[0].Assets[0].Position,
	}, nil
}