package projects
import (
"encoding/json"
"html/template"
"log"
"math"
"os"
"path"
"strings"
)
type Link struct {
Title string
Href string
Class string `json:",omitempty"`
}
type Project struct {
Name string `json:"-"`
Title string
Description string
Shortdesc string
GoGet string `json:",omitempty"`
ReadmePath string `json:",omitempty"`
Git string `json:",omitempty"` // local git repo
License string `json:",omitempty"`
Links []Link
Tags []string
dir string `json:"-"`
FormattedReadme template.HTML `json:"-"`
}
func LoadProject(name string) (p Project, err error) {
f, err := os.Open(name)
if err != nil {
return p, err
}
defer f.Close()
dec := json.NewDecoder(f)
if err := dec.Decode(&p); err != nil {
return p, err
}
p.dir = path.Dir(name)
p.formatReadme()
nameParts := strings.Split(path.Base(name), ".")
p.Name = strings.Join(nameParts[:len(nameParts)-1], ".")
return
}
type ProjectRepo struct {
Dir string
Projects map[string]Project
Tags map[string]map[string]struct{}
Tagcloud map[string]TagcloudElem
}
const TAGCLOUD_SIZE_CATEGORIES = 5
type TagcloudElem struct {
Tag string
Size int
}
func NewProjectRepo(dir string) *ProjectRepo {
return &ProjectRepo{
Dir: dir,
Projects: make(map[string]Project),
Tags: make(map[string]map[string]struct{}),
Tagcloud: make(map[string]TagcloudElem),
}
}
func (repo *ProjectRepo) updateTags() {
tags := make(map[string]map[string]struct{})
tagcounts := make(map[string]int)
maxcount := 0
for name, proj := range repo.Projects {
for _, tag := range proj.Tags {
if _, ok := tags[tag]; !ok {
tags[tag] = make(map[string]struct{})
}
tags[tag][name] = struct{}{}
tagcount := tagcounts[tag] + 1
tagcounts[tag] = tagcount
if tagcount > maxcount {
maxcount = tagcount
}
}
}
tagcloud := make(map[string]TagcloudElem)
if maxcount > 0 {
for tag, count := range tagcounts {
tagcloud[tag] = TagcloudElem{
Tag: tag,
Size: int(math.Ceil((float64(count) / float64(maxcount)) * TAGCLOUD_SIZE_CATEGORIES)),
}
}
}
repo.Tags = tags
repo.Tagcloud = tagcloud
}
func (repo *ProjectRepo) ScanProjects() {
d, err := os.Open(repo.Dir)
if err != nil {
log.Printf("Failed scanning projects: Could not open dir: %s", err)
return
}
defer d.Close()
names, err := d.Readdirnames(0)
if err != nil {
log.Printf("Failed scanning projects: Could not readdir: %s", err)
return
}
projects := make(map[string]Project)
for _, fname := range names {
if path.Ext(fname) != ".json" {
continue
}
p, err := LoadProject(path.Join(repo.Dir, fname))
if err != nil {
log.Printf("Skip project file %s: %s", fname, err)
continue
}
projects[p.Name] = p
}
repo.Projects = projects
repo.updateTags()
}