Skip to content

Commit

Permalink
Add ExactAttachment header
Browse files Browse the repository at this point in the history
  • Loading branch information
csoutherland committed Jun 25, 2020
1 parent e5c50c3 commit 7145cb4
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 18 deletions.
29 changes: 29 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ File in extended format should follow specification
<!-- Parent: <parent 1> -->
<!-- Parent: <parent 2> -->
<!-- Title: <title> -->
<!-- ExactAttachment: <local path> -->
<!-- Attachment: <local path> -->

<page contents>
```
Expand Down Expand Up @@ -61,6 +63,33 @@ follows include tag:
<yaml-data> -->
```

Mark also supports attachments. The standard way involves declaring an
`Attachment` along with the other items in the header, then have any links
start with an `attachment://` pseudo-URL:

```markdown
<!-- Attachment: <path> -->

<beginning of page content>

An attached link is [here](attachment://<path>)
```

The standard attachment mechanism may not work in some circumstances (e.g.
keeping content as close to identical as possible between GitHub and
Confluence), so `ExactAttachment` has been introduced:

```markdown
<!-- ExactAttachment: <path> -->

<beginning of page content>

An attached link is [here](<path>)
```

*NOTE* Be careful with `ExactAttachment`! If your path string is a subset of
another longer string or referenced in text, you may get undesired behavior.

Mark also supports macro definitions, which are defined as regexps which will
be replaced with specified template:

Expand Down
24 changes: 13 additions & 11 deletions pkg/mark/attachment.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,20 +28,22 @@ type Attachment struct {
Path string
Checksum string
Link string
Replace string
}

func ResolveAttachments(
api *confluence.API,
page *confluence.PageInfo,
base string,
names []string,
replacements map[string]string,
) ([]Attachment, error) {
attaches := []Attachment{}
for _, name := range names {
for replace, name := range replacements {
attach := Attachment{
Name: name,
Filename: strings.ReplaceAll(name, "/", "_"),
Path: filepath.Join(base, name),
Replace: replace,
}

checksum, err := getChecksum(attach.Path)
Expand Down Expand Up @@ -160,32 +162,32 @@ func ResolveAttachments(

func CompileAttachmentLinks(markdown []byte, attaches []Attachment) []byte {
links := map[string]string{}
names := []string{}
replaces := []string{}

for _, attach := range attaches {
uri, err := url.ParseRequestURI(attach.Link)
if err != nil {
links[attach.Name] = strings.ReplaceAll("&", "&amp;", attach.Link)
links[attach.Replace] = strings.ReplaceAll("&", "&amp;", attach.Link)
} else {
links[attach.Name] = uri.Path +
links[attach.Replace] = uri.Path +
"?" + url.QueryEscape(uri.Query().Encode())
}

names = append(names, attach.Name)
replaces = append(replaces, attach.Replace)
}

// sort by length so first items will have bigger length
// it's helpful for replacing in case of following names
// attachments/a.jpg
// attachments/a.jpg.jpg
// so we replace longer and then shorter
sort.SliceStable(names, func(i, j int) bool {
return len(names[i]) > len(names[j])
sort.SliceStable(replaces, func(i, j int) bool {
return len(replaces[i]) > len(replaces[j])
})

for _, name := range names {
from := `attachment://` + name
to := links[name]
for _, replace := range replaces {
from := replace
to := links[replace]

log.Debugf(nil, "replacing: %q -> %q", from, to)

Expand Down
19 changes: 12 additions & 7 deletions pkg/mark/meta.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,19 +11,20 @@ import (
)

const (
HeaderParent = `Parent`
HeaderSpace = `Space`
HeaderTitle = `Title`
HeaderLayout = `Layout`
HeaderAttachment = `Attachment`
HeaderParent = `Parent`
HeaderSpace = `Space`
HeaderTitle = `Title`
HeaderLayout = `Layout`
HeaderAttachment = `Attachment`
HeaderExactAttachment = `ExactAttachment`
)

type Meta struct {
Parents []string
Space string
Title string
Layout string
Attachments []string
Attachments map[string]string
}

var (
Expand Down Expand Up @@ -64,6 +65,7 @@ func ExtractMeta(data []byte) (*Meta, []byte, error) {

if meta == nil {
meta = &Meta{}
meta.Attachments = make(map[string]string)
}

header := strings.Title(matches[1])
Expand All @@ -87,7 +89,10 @@ func ExtractMeta(data []byte) (*Meta, []byte, error) {
meta.Layout = strings.TrimSpace(value)

case HeaderAttachment:
meta.Attachments = append(meta.Attachments, value)
meta.Attachments["attachment://"+value] = value

case HeaderExactAttachment:
meta.Attachments[value] = value

default:
log.Errorf(
Expand Down

0 comments on commit 7145cb4

Please sign in to comment.