├── AUTHORS ├── .gitignore ├── templates ├── templates.go └── main.go ├── LICENSE ├── README.md └── main.go /AUTHORS: -------------------------------------------------------------------------------- 1 | The following authors have all licensed their contributions to Femtowiki 2 | under the licensing terms detailed in LICENSE. 3 | 4 | - Sagar Gubbi 5 | 6 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Binaries for programs and plugins 2 | *.exe 3 | *.dll 4 | *.so 5 | *.dylib 6 | 7 | # Test binary, build with `go test -c` 8 | *.test 9 | 10 | # Output of the go coverage tool, specifically when used with LiteIDE 11 | *.out 12 | 13 | # Project-local glide cache, RE: https://github.com/Masterminds/glide/issues/736 14 | .glide/ 15 | 16 | .idea/ 17 | femtowiki* 18 | -------------------------------------------------------------------------------- /templates/templates.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Femtowiki authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | package templates 6 | 7 | import ( 8 | "io" 9 | "log" 10 | "html/template" 11 | "io/ioutil" 12 | ) 13 | 14 | var Main = template.Must(template.New("main").Parse(mainSrc)) 15 | 16 | func OverwriteTemplates(rootDir string) { 17 | mainSrc, err := ioutil.ReadFile(rootDir + "/main.html") 18 | if err == nil { 19 | Main = template.Must(template.New("main").Parse(string(mainSrc))) 20 | } else { 21 | log.Fatalf("[ERROR] Error reading template: %s", err) 22 | } 23 | } 24 | 25 | func Render(wr io.Writer, tmpl *template.Template, data interface{}) { 26 | err := tmpl.Execute(wr, data) 27 | if err != nil { 28 | log.Panicf("[ERROR] Error rendering %s: %s\n", tmpl.Name(), err) 29 | } 30 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2017, Femtowiki authors, see AUTHORS file. 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | * Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | * Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | * Neither the name of the copyright holder nor the names of its 17 | contributors may be used to endorse or promote products derived from 18 | this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /templates/main.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Femtowiki authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | package templates 6 | 7 | const mainSrc = ` 8 | 9 | 10 | 11 | 12 | 13 | {{ .Title }} 14 | 50 | 51 | 52 |
53 | 56 |
57 | {{ .Content }} 58 |
59 | 60 | ` -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | femtowiki 2 | ========= 3 | 4 | [Femtowiki](www.goodoldweb.com/femtowiki/) is a tiny wiki written in golang. 5 | It allows users to create pages using markdown. 6 | The wiki has few dependencies and uses very little javascript. It doesn't need 7 | a database system and can also be used as a static site generator. 8 | Try the latest version hosted [here](https://wiki.goodoldweb.com/). 9 | Please contact [info@goodoldweb.com](mailto:info@goodoldweb.com) if you have any questions or want support. 10 | 11 | How to use 12 | ---------- 13 | 14 | [Download](https://github.com/s-gv/femtowiki/releases) the binary. 15 | 16 | - To use this as a static site generator, do the following: 17 | 18 | Create a few markdown files (with extension .md) in a directory, say `/home/user/wikiroot/`. 19 | 20 | Then, run: 21 | 22 | ``` 23 | ./femtowiki -wikiroot 24 | ``` 25 | 26 | A HTML file is created for every markdown file using a default template (see `templates/` in this repo). 27 | To specify custom templates, use: 28 | 29 | ``` 30 | ./femtowiki -wikiroot -templateroot 31 | ``` 32 | 33 | - If you'd like to be able to edit the wiki in a browser, then create a new user with: 34 | 35 | TODO: Current version does not yet support this! 36 | 37 | ``` 38 | ./femtowiki -createuser -users 39 | ``` 40 | 41 | Start the server: 42 | 43 | ``` 44 | ./femtowiki -wikiroot -users -serve 45 | ``` 46 | 47 | Dependencies 48 | ------------ 49 | 50 | - Go 1.8 (only for compiling) 51 | 52 | Options 53 | ------- 54 | 55 | - `-addr `: Use `./femtowiki -addr :8086` to listen on port 8086. 56 | - `-wikiroot `: Specify directory containing markdown files. 57 | - `-templateroot `: Specify directory containing template files. 58 | - `-users `: Specify file containing list of users. 59 | 60 | Commands 61 | -------- 62 | 63 | - `-help`: Show a list of all commands and options. 64 | - `-createuser`: Create a new user. 65 | - `-changepasswd`: Change password of a user. 66 | - `-serve`: Run the online editor. 67 | 68 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Femtowiki authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style license that can be 3 | // found in the LICENSE file. 4 | 5 | package main 6 | 7 | import ( 8 | "bytes" 9 | "flag" 10 | "html/template" 11 | "io/ioutil" 12 | "log" 13 | "os" 14 | "path/filepath" 15 | "regexp" 16 | "strings" 17 | 18 | "github.com/microcosm-cc/bluemonday" 19 | "github.com/s-gv/femtowiki/templates" 20 | "gopkg.in/russross/blackfriday.v2" 21 | ) 22 | 23 | var titleRegex *regexp.Regexp = regexp.MustCompile("

([^<>/]+)

") 24 | 25 | func renderMd(markdown string) string { 26 | unsafe := blackfriday.Run([]byte(strings.Replace(markdown, "\r\n", "\n", -1))) 27 | html := string(bluemonday.UGCPolicy().SanitizeBytes(unsafe)) 28 | 29 | matches := titleRegex.FindStringSubmatch(html) 30 | title := "Femtowiki" 31 | if len(matches) >= 2 && matches[1] != "" { 32 | title = matches[1] 33 | } 34 | 35 | buf := new(bytes.Buffer) 36 | templates.Render(buf, templates.Main, map[string]interface{}{ 37 | "Title": title, 38 | "Content": template.HTML(html), 39 | }) 40 | 41 | return buf.String() 42 | } 43 | 44 | func main() { 45 | log.SetFlags(log.LstdFlags | log.Lshortfile) 46 | 47 | wikiRoot := flag.String("wikiroot", "", "Root of the wiki") 48 | htmlRoot := flag.String("htmlroot", "", "Root to the folder of generated html files") 49 | templateRoot := flag.String("templateroot", "", "Root of template files") 50 | 51 | flag.Parse() 52 | 53 | if *wikiRoot == "" { 54 | log.Fatalf("[ERROR] Specify wiki root\n") 55 | } 56 | var err error 57 | *wikiRoot, err = filepath.Abs(*wikiRoot) 58 | if err != nil { 59 | log.Fatalf("[ERROR] processing wiki root\n") 60 | } 61 | if *htmlRoot == "" { 62 | *htmlRoot = *wikiRoot 63 | } 64 | 65 | if *templateRoot != "" { 66 | templates.OverwriteTemplates(*templateRoot) 67 | } 68 | 69 | err = filepath.Walk(*wikiRoot, 70 | func(path string, info os.FileInfo, err error) error { 71 | if err != nil { 72 | return err 73 | } 74 | path, err = filepath.Rel(*wikiRoot, path) 75 | if err != nil { 76 | return err 77 | } 78 | if regexp.MustCompile(`(?i).md$`).MatchString(path) { 79 | buf, err := ioutil.ReadFile(*wikiRoot + "/" + path) 80 | if err != nil { 81 | return err 82 | } 83 | md := string(buf) 84 | html := renderMd(md) 85 | 86 | htmlfn := *htmlRoot + "/" + path[:len(path)-3] + ".html" 87 | htmldn := filepath.Dir(htmlfn) 88 | if !isDir(htmldn) { 89 | err = os.Mkdir(htmldn, 0750) 90 | if err != nil && !os.IsExist(err) { 91 | log.Fatal(err) 92 | } 93 | } 94 | ioutil.WriteFile(htmlfn, []byte(html), 0644) 95 | } 96 | return nil 97 | }) 98 | if err != nil { 99 | log.Fatal(err) 100 | } 101 | 102 | } 103 | 104 | func isDir(path string) bool { 105 | info, err := os.Stat(path) 106 | if err != nil { 107 | return false 108 | } 109 | return info.IsDir() 110 | } 111 | --------------------------------------------------------------------------------