Merge pull request #22 from csoutherland/exactattach

Add ExactAttachment header
This commit is contained in:
Egor Kovetskiy 2020-07-19 17:35:58 +03:00 committed by GitHub
commit f39aeb10d7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 54 additions and 18 deletions

View File

@ -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>
```
@ -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:

View File

@ -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)
@ -160,18 +162,18 @@ 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
@ -179,13 +181,13 @@ func CompileAttachmentLinks(markdown []byte, attaches []Attachment) []byte {
// 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)

View File

@ -16,6 +16,7 @@ const (
HeaderTitle = `Title`
HeaderLayout = `Layout`
HeaderAttachment = `Attachment`
HeaderExactAttachment = `ExactAttachment`
)
type Meta struct {
@ -23,7 +24,7 @@ type Meta struct {
Space string
Title string
Layout string
Attachments []string
Attachments map[string]string
}
var (
@ -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])
@ -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(