Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Embed external resources #90

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 11 additions & 3 deletions example.html

Large diffs are not rendered by default.

3 changes: 1 addition & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,8 @@ require (
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
github.com/xeipuuv/gojsonschema v1.1.0
golang.org/x/crypto v0.0.0-20190131182504-b8fe1690c613 // indirect
golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3 // indirect
golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3
golang.org/x/sys v0.0.0-20190204203706-41f3e6584952 // indirect
gopkg.in/src-d/go-billy.v4 v4.3.0 // indirect
gopkg.in/src-d/go-git-fixtures.v3 v3.3.0 // indirect
gopkg.in/src-d/go-git.v4 v4.9.1
)
4 changes: 0 additions & 4 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -380,8 +380,6 @@ github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f h1:J9EGpcZtP
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0=
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ=
github.com/xeipuuv/gojsonschema v0.0.0-20181112162635-ac52e6811b56 h1:yhqBHs09SmmUoNOHc9jgK4a60T3XFRtPAkYxVnqgY50=
github.com/xeipuuv/gojsonschema v0.0.0-20181112162635-ac52e6811b56/go.mod h1:5yf86TLmAcydyeJq5YvxkGPE2fm/u4myDekKRoLuqhs=
github.com/xeipuuv/gojsonschema v1.1.0 h1:ngVtJC9TY/lg0AA/1k48FYhBrhRoFlEmWzsehpNAaZg=
github.com/xeipuuv/gojsonschema v1.1.0/go.mod h1:5yf86TLmAcydyeJq5YvxkGPE2fm/u4myDekKRoLuqhs=
github.com/yosssi/ace v0.0.5 h1:tUkIP/BLdKqrlrPwcmH0shwEEhTRHoGnc1wFIWmaBUA=
Expand Down Expand Up @@ -470,8 +468,6 @@ gopkg.in/src-d/go-billy.v4 v4.2.1/go.mod h1:tm33zBoOwxjYHZIE+OV8bxTWFMJLrconzFMd
gopkg.in/src-d/go-billy.v4 v4.3.0 h1:KtlZ4c1OWbIs4jCv5ZXrTqG8EQocr0g/d4DjNg70aek=
gopkg.in/src-d/go-billy.v4 v4.3.0/go.mod h1:tm33zBoOwxjYHZIE+OV8bxTWFMJLrconzFMd38aARFk=
gopkg.in/src-d/go-git-fixtures.v3 v3.1.1/go.mod h1:dLBcvytrw/TYZsNTWCnkNF2DSIlzWYqTe3rJR56Ac7g=
gopkg.in/src-d/go-git-fixtures.v3 v3.3.0 h1:AxUOwLW3at53ysFqs0Lg+H+8KSQXl7AEHBvWj8wEsT8=
gopkg.in/src-d/go-git-fixtures.v3 v3.3.0/go.mod h1:dLBcvytrw/TYZsNTWCnkNF2DSIlzWYqTe3rJR56Ac7g=
gopkg.in/src-d/go-git.v4 v4.9.1 h1:0oKHJZY8tM7B71378cfTg2c5jmWyNlXvestTT6WfY+4=
gopkg.in/src-d/go-git.v4 v4.9.1/go.mod h1:Vtut8izDyrM8BUVQnzJ+YvmNcem2J89EmfZYCkLokZk=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
Expand Down
75 changes: 75 additions & 0 deletions render/embed.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
package render

import (
"bytes"
"encoding/base64"
"io/ioutil"
"net/http"

"golang.org/x/net/html"
)

func makeDataURL(resourceURL string, client *http.Client) (string, error) {
response, err := client.Get(resourceURL)
if err != nil {
return "", err
}

contentType := response.Header.Get("Content-type")
if contentType == "" {
contentType = "application/octet-stream"
}

content, err := ioutil.ReadAll(response.Body)
if err != nil {
return "", err
}
contentBase64 := base64.StdEncoding.EncodeToString(content)

dataURL := "data:" + contentType + ";base64," + contentBase64
return dataURL, nil
}

func embedHTMLNode(node *html.Node, baseURL string, client *http.Client) error {
if node.Type == html.ElementNode {
for index, attr := range node.Attr {
if attr.Key == "href" || attr.Key == "src" {
resourceURL, err := absURL(baseURL, attr.Val)
if err != nil {
return nil
}
dataURL, err := makeDataURL(resourceURL, client)
if err != nil {
return err
}
node.Attr[index].Val = dataURL
}
}
}

for child := node.FirstChild; child != nil; child = child.NextSibling {
if err := embedHTMLNode(child, baseURL, client); err != nil {
return err
}
}

return nil
}

func embedHTML(pageHTML []byte, pageURL string, client *http.Client) ([]byte, error) {
node, err := html.Parse(bytes.NewReader(pageHTML))
if err != nil {
return nil, err
}

if err := embedHTMLNode(node, pageURL, client); err != nil {
return nil, err
}

embeddedHTML := &bytes.Buffer{}
if err := html.Render(embeddedHTML, node); err != nil {
return nil, err
}

return embeddedHTML.Bytes(), nil
}
65 changes: 65 additions & 0 deletions render/http.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package render

import (
"net/http"
"net/url"
"path"
)

func absURL(baseURL, resourceURL string) (string, error) {
base, err := url.Parse(baseURL)
if err != nil {
return "", err
}
resource, err := base.Parse(resourceURL)
if err != nil {
return "", err
}
return resource.String(), nil
}

type transport struct {
siteURL *url.URL
localTransport http.RoundTripper
siteTransport http.RoundTripper
remoteTransport http.RoundTripper
}

func newTransport(site hugoSite) (*transport, error) {
t := &transport{}

siteURL, err := url.Parse(site.config.BaseURL)
if err != nil {
return nil, err
}
t.siteURL = siteURL

t.localTransport = http.NewFileTransport(http.Dir("/"))
publicDir := path.Join(site.dir, "public")
t.siteTransport = http.NewFileTransport(http.Dir(publicDir))
t.remoteTransport = &http.Transport{}

return t, nil
}

func (t *transport) RoundTrip(req *http.Request) (*http.Response, error) {
reqURL := req.URL
if reqURL.Scheme == "file" {
return t.localTransport.RoundTrip(req)
}
if reqURL.Host == "" || reqURL.Host == t.siteURL.Host {
return t.siteTransport.RoundTrip(req)
}
return t.remoteTransport.RoundTrip(req)
}

func newClient(site hugoSite) (*http.Client, error) {
trans, err := newTransport(site)
if err != nil {
return nil, err
}
client := &http.Client{
Transport: trans,
}
return client, nil
}
98 changes: 98 additions & 0 deletions render/hugo.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
package render

import (
"encoding/json"
"io/ioutil"
"net/url"
"os"
"path"

"github.com/gohugoio/hugo/commands"
)

type CouldNotReadPublicError struct {
url *url.URL
dir string
}

func (e *CouldNotReadPublicError) Error() string {
return "Could not find " + e.url.String() + " in " + e.dir
}

type contentFrontmatter struct {
Layout string `json:"layout"`
}

type hugoConfig struct {
DisableKinds []string `json:"disableKinds"`
Theme string `json:"theme"`
BaseURL string `json:"baseURL"`
Title string `json:"title"`
}

func newHugoConfig() hugoConfig {
config := hugoConfig{}
config.DisableKinds = []string{"taxonomy", "taxonomyTerm", "category", "sitemap", "RSS", "404", "robotsTXT", "home", "section"}
config.BaseURL = "http://example.org/"
config.Title = "resumic"
return config
}

type hugoSite struct {
dir string
config hugoConfig
}

func initHugoSite(siteDir string) (hugoSite, error) {
site := hugoSite{
dir: siteDir,
}
if err := os.MkdirAll(site.dir, 0700); err != nil {
return site, err
}

site.config = newHugoConfig()
configJSON, err := json.MarshalIndent(site.config, "", " ")
if err != nil {
return site, err
}
configPath := path.Join(site.dir, "config.json")
if err := ioutil.WriteFile(configPath, configJSON, 0600); err != nil {
return site, err
}

return site, nil
}

func (s hugoSite) writeResumeJSON(resumeJSON []byte, resumeName string) error {
dataDir := path.Join(s.dir, "data", "resumic")
if err := os.MkdirAll(dataDir, 0700); err != nil {
return err
}
dataPath := path.Join(dataDir, resumeName+".json")
if err := ioutil.WriteFile(dataPath, resumeJSON, 0600); err != nil {
return err
}

content := contentFrontmatter{}
content.Layout = "resumic"
contentJSON, err := json.MarshalIndent(content, "", " ")
if err != nil {
return err
}
contentDir := path.Join(s.dir, "content", "resumic")
if err := os.MkdirAll(contentDir, 0700); err != nil {
return err
}
contentPath := path.Join(contentDir, resumeName+".md")
return ioutil.WriteFile(contentPath, contentJSON, 0600)
}

func (s hugoSite) getResumeURL(resumeName string) (string, error) {
return absURL(s.config.BaseURL, "/resumic/"+resumeName)
}

func (s hugoSite) build(themeDir string) error {
resp := commands.Execute([]string{"--quiet", "--source", s.dir, "--themesDir", themeDir})
return resp.Err
}
58 changes: 15 additions & 43 deletions render/render.go
Original file line number Diff line number Diff line change
@@ -1,80 +1,52 @@
package render

import (
"encoding/json"
"io/ioutil"
"os"
"path"

"github.com/gohugoio/hugo/commands"
"github.com/resumic/schema/schema"
)

type siteConfig struct {
DisableKinds []string `json:"disableKinds"`
Theme string `json:"theme"`
}

type frontmatter struct {
Layout string `json:"layout"`
}

func build(root, themePath string) error {
resp := commands.Execute([]string{"--quiet", "-s", root, "--themesDir", themePath})
return resp.Err
}

func RenderHTML(resume []byte, themePath string) ([]byte, error) {
sitePath, err := ioutil.TempDir(os.TempDir(), "resumic")
if err != nil {
func RenderHTML(resumeJSON []byte, themeDir string) ([]byte, error) {
if err := schema.ValidateResume(resumeJSON); err != nil {
return nil, err
}
defer os.RemoveAll(sitePath)

config := siteConfig{}
config.DisableKinds = []string{"taxonomy", "taxonomyTerm", "category", "sitemap", "RSS", "404", "robotsTXT", "home", "section"}

configJSON, err := json.MarshalIndent(config, "", " ")
siteDir, err := ioutil.TempDir(os.TempDir(), "resumic")
if err != nil {
return nil, err
}
configPath := path.Join(sitePath, "config.json")
err = ioutil.WriteFile(configPath, configJSON, 0600)
defer os.RemoveAll(siteDir)
site, err := initHugoSite(siteDir)
if err != nil {
return nil, err
}

dataPath := path.Join(sitePath, "data", "resumic", "resume.json")
err = os.MkdirAll(path.Dir(dataPath), 0700)
if err != nil {
resumeName := "resume"
if err := site.writeResumeJSON(resumeJSON, resumeName); err != nil {
return nil, err
}
err = ioutil.WriteFile(dataPath, resume, 0600)
resumeURL, err := site.getResumeURL(resumeName)
if err != nil {
return nil, err
}

content := frontmatter{}
content.Layout = "resumic"

contentJSON, err := json.MarshalIndent(content, "", " ")
if err != nil {
if err := site.build(themeDir); err != nil {
return nil, err
}
contentPath := path.Join(sitePath, "content", "resumic", "resume.md")
err = os.MkdirAll(path.Dir(contentPath), 0700)

client, err := newClient(site)
if err != nil {
return nil, err
}
err = ioutil.WriteFile(contentPath, contentJSON, 0600)
response, err := client.Get(resumeURL)
if err != nil {
return nil, err
}

err = build(sitePath, themePath)
resumeHTML, err := ioutil.ReadAll(response.Body)
if err != nil {
return nil, err
}

htmlPath := path.Join(sitePath, "public", "resumic", "resume", "index.html")
return ioutil.ReadFile(htmlPath)
return embedHTML(resumeHTML, resumeURL, client)
}
9 changes: 9 additions & 0 deletions theme/defaults/test-theme/layouts/resumic/single.html
Original file line number Diff line number Diff line change
@@ -1,6 +1,15 @@
<html>
<head>
<link rel="stylesheet" type="text/css" href="/style.css">
</head>
<body>
{{ $resume := index $.Site.Data.resumic .File.BaseFileName }}
{{ $resume.personal.name }} - {{ $resume.core.title }}

<div>
<p> Powerd By <a href="https://github.com/resumic/schema">resumic</a></p>
<img src="/resumic.jpg" />
</div>
<script src="/script.js"></script>
</body>
</html>
Binary file added theme/defaults/test-theme/static/resumic.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions theme/defaults/test-theme/static/script.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
document.addEventListener("DOMContentLoaded", function(event) {
console.log("Hi!")
});
3 changes: 3 additions & 0 deletions theme/defaults/test-theme/static/style.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
body {
background: blue;
}