mirror of
https://github.com/kovetskiy/mark.git
synced 2025-04-24 05:42:40 +08:00
wip: attachments
This commit is contained in:
parent
5f582e51e6
commit
76ddde31ab
87
main.go
87
main.go
@ -12,7 +12,7 @@ import (
|
|||||||
"github.com/kovetskiy/lorg"
|
"github.com/kovetskiy/lorg"
|
||||||
"github.com/kovetskiy/mark/pkg/confluence"
|
"github.com/kovetskiy/mark/pkg/confluence"
|
||||||
"github.com/kovetskiy/mark/pkg/mark"
|
"github.com/kovetskiy/mark/pkg/mark"
|
||||||
"github.com/reconquest/colorgful"
|
"github.com/reconquest/cog"
|
||||||
"github.com/reconquest/karma-go"
|
"github.com/reconquest/karma-go"
|
||||||
"github.com/zazab/zhash"
|
"github.com/zazab/zhash"
|
||||||
)
|
)
|
||||||
@ -32,12 +32,6 @@ located in ~/.config/mark with following format:
|
|||||||
where 'smith' it's your username, 'matrixishere' it's your password and
|
where 'smith' it's your username, 'matrixishere' it's your password and
|
||||||
'http://confluence.local' is base URL for your Confluence instance.
|
'http://confluence.local' is base URL for your Confluence instance.
|
||||||
|
|
||||||
Mark can read Confluence page URL and markdown file path from another specified
|
|
||||||
configuration file, which you can specify using -c <file> flag. It is very
|
|
||||||
usable for git hooks. That file should have following format:
|
|
||||||
url = "http://confluence.local/pages/viewpage.action?pageId=123456"
|
|
||||||
file = "docs/README.md"
|
|
||||||
|
|
||||||
Mark understands extended file format, which, still being valid markdown,
|
Mark understands extended file format, which, still being valid markdown,
|
||||||
contains several metadata headers, which can be used to locate page inside
|
contains several metadata headers, which can be used to locate page inside
|
||||||
Confluence instance and update it accordingly.
|
Confluence instance and update it accordingly.
|
||||||
@ -88,24 +82,21 @@ Options:
|
|||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
logger = lorg.NewLog()
|
log *cog.Logger
|
||||||
)
|
)
|
||||||
|
|
||||||
func initLogger(trace bool) {
|
func initlog(trace bool) {
|
||||||
|
stderr := lorg.NewLog()
|
||||||
|
stderr.SetIndentLines(true)
|
||||||
|
stderr.SetFormat(
|
||||||
|
lorg.NewFormat("${time} ${level:[%s]:right:short} ${prefix}%s"),
|
||||||
|
)
|
||||||
|
|
||||||
|
log = cog.NewLogger(stderr)
|
||||||
|
|
||||||
if trace {
|
if trace {
|
||||||
logger.SetLevel(lorg.LevelTrace)
|
log.SetLevel(lorg.LevelTrace)
|
||||||
}
|
}
|
||||||
|
|
||||||
logFormat := `${time} ${level:[%s]:right:true} %s`
|
|
||||||
|
|
||||||
if format := os.Getenv("LOG_FORMAT"); format != "" {
|
|
||||||
logFormat = format
|
|
||||||
}
|
|
||||||
|
|
||||||
logger.SetFormat(colorgful.MustApplyDefaultTheme(
|
|
||||||
logFormat,
|
|
||||||
colorgful.Default,
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
@ -121,21 +112,21 @@ func main() {
|
|||||||
trace = args["--trace"].(bool)
|
trace = args["--trace"].(bool)
|
||||||
)
|
)
|
||||||
|
|
||||||
initLogger(trace)
|
initlog(trace)
|
||||||
|
|
||||||
config, err := getConfig(filepath.Join(os.Getenv("HOME"), ".config/mark"))
|
config, err := getConfig(filepath.Join(os.Getenv("HOME"), ".config/mark"))
|
||||||
if err != nil && !os.IsNotExist(err) {
|
if err != nil && !os.IsNotExist(err) {
|
||||||
logger.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
markdownData, err := ioutil.ReadFile(targetFile)
|
markdownData, err := ioutil.ReadFile(targetFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
meta, err := mark.ExtractMeta(markdownData)
|
meta, err := mark.ExtractMeta(markdownData)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
htmlData := mark.CompileMarkdown(markdownData)
|
htmlData := mark.CompileMarkdown(markdownData)
|
||||||
@ -147,13 +138,14 @@ func main() {
|
|||||||
|
|
||||||
creds, err := GetCredentials(args, config)
|
creds, err := GetCredentials(args, config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
api := confluence.NewAPI(creds.BaseURL, creds.Username, creds.Password)
|
api := confluence.NewAPI(creds.BaseURL, creds.Username, creds.Password)
|
||||||
|
|
||||||
if creds.PageID != "" && meta != nil {
|
if creds.PageID != "" && meta != nil {
|
||||||
logger.Warningf(
|
log.Warningf(
|
||||||
|
nil,
|
||||||
`specified file contains metadata, `+
|
`specified file contains metadata, `+
|
||||||
`but it will be ignored due specified command line URL`,
|
`but it will be ignored due specified command line URL`,
|
||||||
)
|
)
|
||||||
@ -162,7 +154,8 @@ func main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if creds.PageID == "" && meta == nil {
|
if creds.PageID == "" && meta == nil {
|
||||||
logger.Fatalf(
|
log.Fatalf(
|
||||||
|
nil,
|
||||||
`specified file doesn't contain metadata `+
|
`specified file doesn't contain metadata `+
|
||||||
`and URL is not specified via command line `+
|
`and URL is not specified via command line `+
|
||||||
`or doesn't contain pageId GET-parameter`,
|
`or doesn't contain pageId GET-parameter`,
|
||||||
@ -174,34 +167,40 @@ func main() {
|
|||||||
if meta != nil {
|
if meta != nil {
|
||||||
page, err := resolvePage(api, meta)
|
page, err := resolvePage(api, meta)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Fatal(err)
|
log.Fatalf(
|
||||||
|
karma.Describe("title", meta.Title).Reason(err),
|
||||||
|
"unable to resolve page",
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
target = page
|
target = page
|
||||||
} else {
|
} else {
|
||||||
if creds.PageID == "" {
|
if creds.PageID == "" {
|
||||||
logger.Fatalf("URL should provide 'pageId' GET-parameter")
|
log.Fatalf(nil, "URL should provide 'pageId' GET-parameter")
|
||||||
}
|
}
|
||||||
|
|
||||||
page, err := api.GetPageByID(creds.PageID)
|
page, err := api.GetPageByID(creds.PageID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Fatal(err)
|
log.Fatalf(err, "unable to retrieve page by id")
|
||||||
}
|
}
|
||||||
|
|
||||||
target = page
|
target = page
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mark.ResolveAttachments(api, target, ".", meta.Attachments)
|
||||||
|
|
||||||
err = api.UpdatePage(
|
err = api.UpdatePage(
|
||||||
target,
|
target,
|
||||||
MacroLayout{meta.Layout, [][]byte{htmlData}}.Render(),
|
MacroLayout{meta.Layout, [][]byte{htmlData}}.Render(),
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if editLock {
|
if editLock {
|
||||||
logger.Infof(
|
log.Infof(
|
||||||
`edit locked on page '%s' by user '%s' to prevent manual edits`,
|
nil,
|
||||||
|
`edit locked on page %q by user %q to prevent manual edits`,
|
||||||
target.Title,
|
target.Title,
|
||||||
creds.Username,
|
creds.Username,
|
||||||
)
|
)
|
||||||
@ -214,7 +213,7 @@ func main() {
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -233,7 +232,7 @@ func resolvePage(
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, karma.Format(
|
return nil, karma.Format(
|
||||||
err,
|
err,
|
||||||
"error during finding page '%s': %s",
|
"error during finding page %q",
|
||||||
meta.Title,
|
meta.Title,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -254,8 +253,9 @@ func resolvePage(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if page == nil {
|
if page == nil {
|
||||||
logger.Warningf(
|
log.Warningf(
|
||||||
"page '%s' is not found ",
|
nil,
|
||||||
|
"page %q is not found ",
|
||||||
meta.Parents[len(ancestry)-1],
|
meta.Parents[len(ancestry)-1],
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -263,7 +263,8 @@ func resolvePage(
|
|||||||
path := meta.Parents
|
path := meta.Parents
|
||||||
path = append(path, meta.Title)
|
path = append(path, meta.Title)
|
||||||
|
|
||||||
logger.Debugf(
|
log.Debugf(
|
||||||
|
nil,
|
||||||
"resolving page path: ??? > %s",
|
"resolving page path: ??? > %s",
|
||||||
strings.Join(path, ` > `),
|
strings.Join(path, ` > `),
|
||||||
)
|
)
|
||||||
@ -277,7 +278,7 @@ func resolvePage(
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, karma.Format(
|
return nil, karma.Format(
|
||||||
err,
|
err,
|
||||||
"can't create ancestry tree: %s; error: %s",
|
"can't create ancestry tree: %s",
|
||||||
strings.Join(meta.Parents, ` > `),
|
strings.Join(meta.Parents, ` > `),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -289,7 +290,8 @@ func resolvePage(
|
|||||||
|
|
||||||
titles = append(titles, parent.Title)
|
titles = append(titles, parent.Title)
|
||||||
|
|
||||||
logger.Infof(
|
log.Infof(
|
||||||
|
nil,
|
||||||
"page will be stored under path: %s > %s",
|
"page will be stored under path: %s > %s",
|
||||||
strings.Join(titles, ` > `),
|
strings.Join(titles, ` > `),
|
||||||
meta.Title,
|
meta.Title,
|
||||||
@ -300,7 +302,7 @@ func resolvePage(
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, karma.Format(
|
return nil, karma.Format(
|
||||||
err,
|
err,
|
||||||
"can't create page '%s': %s",
|
"can't create page %q",
|
||||||
meta.Title,
|
meta.Title,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -322,6 +324,7 @@ func getConfig(path string) (zhash.Hash, error) {
|
|||||||
return zhash.NewHash(), karma.Format(
|
return zhash.NewHash(), karma.Format(
|
||||||
err,
|
err,
|
||||||
"can't decode toml file: %s",
|
"can't decode toml file: %s",
|
||||||
|
path,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,12 +1,31 @@
|
|||||||
package confluence
|
package confluence
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
|
||||||
"github.com/bndr/gopencils"
|
"github.com/bndr/gopencils"
|
||||||
|
"github.com/kovetskiy/lorg"
|
||||||
|
"github.com/reconquest/cog"
|
||||||
|
"github.com/reconquest/karma-go"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func discarder() *lorg.Log {
|
||||||
|
stderr := lorg.NewLog()
|
||||||
|
stderr.SetOutput(ioutil.Discard)
|
||||||
|
return stderr
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
log = cog.NewLogger(discarder())
|
||||||
|
)
|
||||||
|
|
||||||
|
func SetLogger(logger *cog.Logger) {
|
||||||
|
log = logger
|
||||||
|
}
|
||||||
|
|
||||||
type RestrictionOperation string
|
type RestrictionOperation string
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -61,16 +80,20 @@ func NewAPI(baseURL string, username string, password string) *API {
|
|||||||
func (api *API) FindRootPage(space string) (*PageInfo, error) {
|
func (api *API) FindRootPage(space string) (*PageInfo, error) {
|
||||||
page, err := api.FindPage(space, ``)
|
page, err := api.FindPage(space, ``)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf(
|
return nil, karma.Format(
|
||||||
`can't obtain first page from space '%s': %s`,
|
|
||||||
space,
|
|
||||||
err,
|
err,
|
||||||
|
"can't obtain first page from space %q",
|
||||||
|
space,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if page == nil {
|
||||||
|
return nil, errors.New("no such space")
|
||||||
|
}
|
||||||
|
|
||||||
if len(page.Ancestors) == 0 {
|
if len(page.Ancestors) == 0 {
|
||||||
return nil, fmt.Errorf(
|
return nil, fmt.Errorf(
|
||||||
"page '%s' from space '%s' has no parents",
|
"page %q from space %q has no parents",
|
||||||
page.Title,
|
page.Title,
|
||||||
space,
|
space,
|
||||||
)
|
)
|
||||||
@ -99,20 +122,14 @@ func (api *API) FindPage(space string, title string) (*PageInfo, error) {
|
|||||||
request, err := api.rest.Res(
|
request, err := api.rest.Res(
|
||||||
"content/", &result,
|
"content/", &result,
|
||||||
).Get(payload)
|
).Get(payload)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if request.Raw.StatusCode == 401 {
|
// allow 404 because it's fine if page is not found,
|
||||||
return nil, fmt.Errorf("authentification failed")
|
// the function will return nil, nil
|
||||||
}
|
if request.Raw.StatusCode != 404 && request.Raw.StatusCode != 200 {
|
||||||
|
return nil, newErrorStatusNotOK(request)
|
||||||
if request.Raw.StatusCode != 200 {
|
|
||||||
return nil, fmt.Errorf(
|
|
||||||
"Confluence REST API returns unexpected non-200 HTTP status: %s",
|
|
||||||
request.Raw.Status,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(result.Results) == 0 {
|
if len(result.Results) == 0 {
|
||||||
@ -122,31 +139,42 @@ func (api *API) FindPage(space string, title string) (*PageInfo, error) {
|
|||||||
return &result.Results[0], nil
|
return &result.Results[0], nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (api *API) GetAttachments(pageID string) error {
|
||||||
|
result := map[string]interface{}{}
|
||||||
|
|
||||||
|
payload := map[string]string{
|
||||||
|
"expand": "version,container",
|
||||||
|
}
|
||||||
|
|
||||||
|
request, err := api.rest.Res(
|
||||||
|
"content/"+pageID+"/child/attachment", &result,
|
||||||
|
).Get(payload)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if request.Raw.StatusCode != 200 {
|
||||||
|
return newErrorStatusNotOK(request)
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
marshaledXXX, _ := json.MarshalIndent(result, "", " ")
|
||||||
|
fmt.Printf("result: %s\n", string(marshaledXXX))
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (api *API) GetPageByID(pageID string) (*PageInfo, error) {
|
func (api *API) GetPageByID(pageID string) (*PageInfo, error) {
|
||||||
request, err := api.rest.Res(
|
request, err := api.rest.Res(
|
||||||
"content/"+pageID, &PageInfo{},
|
"content/"+pageID, &PageInfo{},
|
||||||
).Get(map[string]string{"expand": "ancestors,version"})
|
).Get(map[string]string{"expand": "ancestors,version"})
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if request.Raw.StatusCode == 401 {
|
|
||||||
return nil, fmt.Errorf("authentification failed")
|
|
||||||
}
|
|
||||||
|
|
||||||
if request.Raw.StatusCode == 404 {
|
|
||||||
return nil, fmt.Errorf(
|
|
||||||
"page with id '%s' not found, Confluence REST API returns 404",
|
|
||||||
pageID,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
if request.Raw.StatusCode != 200 {
|
if request.Raw.StatusCode != 200 {
|
||||||
return nil, fmt.Errorf(
|
return nil, newErrorStatusNotOK(request)
|
||||||
"Confluence REST API returns unexpected HTTP status: %s",
|
|
||||||
request.Raw.Status,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return request.Response.(*PageInfo), nil
|
return request.Response.(*PageInfo), nil
|
||||||
@ -186,14 +214,7 @@ func (api *API) CreatePage(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if request.Raw.StatusCode != 200 {
|
if request.Raw.StatusCode != 200 {
|
||||||
output, _ := ioutil.ReadAll(request.Raw.Body)
|
return nil, newErrorStatusNotOK(request)
|
||||||
defer request.Raw.Body.Close()
|
|
||||||
|
|
||||||
return nil, fmt.Errorf(
|
|
||||||
"Confluence REST API returns unexpected non-200 HTTP status: %s, "+
|
|
||||||
"output: %s",
|
|
||||||
request.Raw.Status, output,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return request.Response.(*PageInfo), nil
|
return request.Response.(*PageInfo), nil
|
||||||
@ -206,7 +227,7 @@ func (api *API) UpdatePage(
|
|||||||
|
|
||||||
if len(page.Ancestors) == 0 {
|
if len(page.Ancestors) == 0 {
|
||||||
return fmt.Errorf(
|
return fmt.Errorf(
|
||||||
"page '%s' info does not contain any information about parents",
|
"page %q info does not contain any information about parents",
|
||||||
page.ID,
|
page.ID,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -241,14 +262,7 @@ func (api *API) UpdatePage(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if request.Raw.StatusCode != 200 {
|
if request.Raw.StatusCode != 200 {
|
||||||
output, _ := ioutil.ReadAll(request.Raw.Body)
|
return newErrorStatusNotOK(request)
|
||||||
defer request.Raw.Body.Close()
|
|
||||||
|
|
||||||
return fmt.Errorf(
|
|
||||||
"Confluence REST API returns unexpected non-200 HTTP status: %s, "+
|
|
||||||
"output: %s",
|
|
||||||
request.Raw.Status, output,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@ -273,14 +287,7 @@ func (api *API) SetPagePermissions(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if request.Raw.StatusCode != 200 {
|
if request.Raw.StatusCode != 200 {
|
||||||
output, _ := ioutil.ReadAll(request.Raw.Body)
|
return newErrorStatusNotOK(request)
|
||||||
defer request.Raw.Body.Close()
|
|
||||||
|
|
||||||
return fmt.Errorf(
|
|
||||||
"Confluence JSON RPC returns unexpected non-200 HTTP status: %s, "+
|
|
||||||
"output: %s",
|
|
||||||
request.Raw.Status, output,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if success, ok := result.(bool); !ok || !success {
|
if success, ok := result.(bool); !ok || !success {
|
||||||
@ -292,3 +299,26 @@ func (api *API) SetPagePermissions(
|
|||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func newErrorStatusNotOK(request *gopencils.Resource) error {
|
||||||
|
if request.Raw.StatusCode == 401 {
|
||||||
|
return errors.New(
|
||||||
|
"Confluence API returned unexpected status: 401 (Unauthorized)",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if request.Raw.StatusCode == 404 {
|
||||||
|
return errors.New(
|
||||||
|
"Confluence API returned unexpected status: 404 (Not Found)",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
output, _ := ioutil.ReadAll(request.Raw.Body)
|
||||||
|
defer request.Raw.Body.Close()
|
||||||
|
|
||||||
|
return fmt.Errorf(
|
||||||
|
"Confluence API returned unexpected status: %v, "+
|
||||||
|
"output: %s",
|
||||||
|
request.Raw.Status, output,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
@ -5,6 +5,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/kovetskiy/mark/pkg/confluence"
|
"github.com/kovetskiy/mark/pkg/confluence"
|
||||||
|
"github.com/reconquest/faces/logger"
|
||||||
"github.com/reconquest/karma-go"
|
"github.com/reconquest/karma-go"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -22,7 +23,7 @@ func EnsureAncestry(
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, karma.Format(
|
return nil, karma.Format(
|
||||||
err,
|
err,
|
||||||
`error during finding parent page with title '%s': %s`,
|
`error during finding parent page with title %q`,
|
||||||
title,
|
title,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -31,7 +32,7 @@ func EnsureAncestry(
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.Tracef("parent page '%s' exists: %s", title, page.Links.Full)
|
log.Tracef(nil, "parent page %q exists: %s", title, page.Links.Full)
|
||||||
|
|
||||||
rest = ancestry[i:]
|
rest = ancestry[i:]
|
||||||
parent = page
|
parent = page
|
||||||
@ -44,19 +45,19 @@ func EnsureAncestry(
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, karma.Format(
|
return nil, karma.Format(
|
||||||
err,
|
err,
|
||||||
"can't find root page for space '%s': %s", space,
|
"can't find root page for space %q",
|
||||||
|
space,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
parent = page
|
parent = page
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(rest) == 0 {
|
if len(rest) == 0 {
|
||||||
return parent, nil
|
return parent, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.Debugf(
|
logger.Debugf(
|
||||||
"empty pages under '%s' to be created: %s",
|
"empty pages under %q to be created: %s",
|
||||||
parent.Title,
|
parent.Title,
|
||||||
strings.Join(rest, ` > `),
|
strings.Join(rest, ` > `),
|
||||||
)
|
)
|
||||||
@ -66,7 +67,7 @@ func EnsureAncestry(
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, karma.Format(
|
return nil, karma.Format(
|
||||||
err,
|
err,
|
||||||
`error during creating parent page with title '%s': %s`,
|
`error during creating parent page with title %q`,
|
||||||
title,
|
title,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -92,12 +93,12 @@ func ValidateAncestry(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if len(page.Ancestors) < 1 {
|
if len(page.Ancestors) < 1 {
|
||||||
return nil, fmt.Errorf(`page '%s' has no parents`, page.Title)
|
return nil, fmt.Errorf(`page %q has no parents`, page.Title)
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(page.Ancestors) < len(ancestry) {
|
if len(page.Ancestors) < len(ancestry) {
|
||||||
return nil, fmt.Errorf(
|
return nil, fmt.Errorf(
|
||||||
"page '%s' has fewer parents than specified: %s",
|
"page %q has fewer parents than specified: %s",
|
||||||
page.Title,
|
page.Title,
|
||||||
strings.Join(ancestry, ` > `),
|
strings.Join(ancestry, ` > `),
|
||||||
)
|
)
|
||||||
@ -108,7 +109,7 @@ func ValidateAncestry(
|
|||||||
if ancestor.Title != ancestry[i] {
|
if ancestor.Title != ancestry[i] {
|
||||||
return nil, fmt.Errorf(
|
return nil, fmt.Errorf(
|
||||||
"broken ancestry tree; expected tree: %s; "+
|
"broken ancestry tree; expected tree: %s; "+
|
||||||
"encountered '%s' at position of '%s'",
|
"encountered %q at position of %q",
|
||||||
strings.Join(ancestry, ` > `),
|
strings.Join(ancestry, ` > `),
|
||||||
ancestor.Title,
|
ancestor.Title,
|
||||||
ancestry[i],
|
ancestry[i],
|
||||||
|
19
pkg/mark/attachment.go
Normal file
19
pkg/mark/attachment.go
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
package mark
|
||||||
|
|
||||||
|
import "github.com/kovetskiy/mark/pkg/confluence"
|
||||||
|
|
||||||
|
type Attachment struct {
|
||||||
|
Name string
|
||||||
|
}
|
||||||
|
|
||||||
|
func ResolveAttachments(
|
||||||
|
api *confluence.API,
|
||||||
|
page *confluence.PageInfo,
|
||||||
|
base string,
|
||||||
|
names []string,
|
||||||
|
) {
|
||||||
|
err := api.GetAttachments(page.ID)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}
|
@ -3,19 +3,11 @@ package mark
|
|||||||
import (
|
import (
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/kovetskiy/lorg"
|
|
||||||
"github.com/kovetskiy/mark/pkg/confluence"
|
"github.com/kovetskiy/mark/pkg/confluence"
|
||||||
|
"github.com/reconquest/faces/logger"
|
||||||
"github.com/reconquest/karma-go"
|
"github.com/reconquest/karma-go"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
|
||||||
logger lorg.Logger = lorg.NewDiscarder()
|
|
||||||
)
|
|
||||||
|
|
||||||
func SetLogger(log lorg.Logger) {
|
|
||||||
logger = log
|
|
||||||
}
|
|
||||||
|
|
||||||
func ResolvePage(
|
func ResolvePage(
|
||||||
api *confluence.API,
|
api *confluence.API,
|
||||||
meta *Meta,
|
meta *Meta,
|
||||||
@ -24,7 +16,7 @@ func ResolvePage(
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, karma.Format(
|
return nil, karma.Format(
|
||||||
err,
|
err,
|
||||||
"error during finding page '%s': %s",
|
"error while finding page %q",
|
||||||
meta.Title,
|
meta.Title,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -45,8 +37,9 @@ func ResolvePage(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if page == nil {
|
if page == nil {
|
||||||
logger.Warningf(
|
log.Warningf(
|
||||||
"page '%s' is not found ",
|
nil,
|
||||||
|
"page %q is not found ",
|
||||||
meta.Parents[len(ancestry)-1],
|
meta.Parents[len(ancestry)-1],
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -68,7 +61,7 @@ func ResolvePage(
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, karma.Format(
|
return nil, karma.Format(
|
||||||
err,
|
err,
|
||||||
"can't create ancestry tree: %s; error: %s",
|
"can't create ancestry tree: %s",
|
||||||
strings.Join(meta.Parents, ` > `),
|
strings.Join(meta.Parents, ` > `),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -80,7 +73,8 @@ func ResolvePage(
|
|||||||
|
|
||||||
titles = append(titles, parent.Title)
|
titles = append(titles, parent.Title)
|
||||||
|
|
||||||
logger.Infof(
|
log.Infof(
|
||||||
|
nil,
|
||||||
"page will be stored under path: %s > %s",
|
"page will be stored under path: %s > %s",
|
||||||
strings.Join(titles, ` > `),
|
strings.Join(titles, ` > `),
|
||||||
meta.Title,
|
meta.Title,
|
||||||
|
@ -4,15 +4,34 @@ import (
|
|||||||
"bufio"
|
"bufio"
|
||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/kovetskiy/lorg"
|
||||||
|
"github.com/reconquest/cog"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func discarder() *lorg.Log {
|
||||||
|
stderr := lorg.NewLog()
|
||||||
|
stderr.SetOutput(ioutil.Discard)
|
||||||
|
return stderr
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
log = cog.NewLogger(discarder())
|
||||||
|
)
|
||||||
|
|
||||||
|
func SetLogger(logger *cog.Logger) {
|
||||||
|
log = logger
|
||||||
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
HeaderParent string = `Parent`
|
HeaderParent = `Parent`
|
||||||
HeaderSpace = `Space`
|
HeaderSpace = `Space`
|
||||||
HeaderTitle = `Title`
|
HeaderTitle = `Title`
|
||||||
HeaderLayout = `Layout`
|
HeaderLayout = `Layout`
|
||||||
|
HeaderAttachment = `Attachment`
|
||||||
)
|
)
|
||||||
|
|
||||||
type Meta struct {
|
type Meta struct {
|
||||||
@ -20,6 +39,7 @@ type Meta struct {
|
|||||||
Space string
|
Space string
|
||||||
Title string
|
Title string
|
||||||
Layout string
|
Layout string
|
||||||
|
Attachments []string
|
||||||
}
|
}
|
||||||
|
|
||||||
func ExtractMeta(data []byte) (*Meta, error) {
|
func ExtractMeta(data []byte) (*Meta, error) {
|
||||||
@ -46,22 +66,31 @@ func ExtractMeta(data []byte) (*Meta, error) {
|
|||||||
|
|
||||||
header := strings.Title(matches[1])
|
header := strings.Title(matches[1])
|
||||||
|
|
||||||
|
var value string
|
||||||
|
if len(matches) > 1 {
|
||||||
|
value = strings.TrimSpace(matches[2])
|
||||||
|
}
|
||||||
|
|
||||||
switch header {
|
switch header {
|
||||||
case HeaderParent:
|
case HeaderParent:
|
||||||
meta.Parents = append(meta.Parents, matches[2])
|
meta.Parents = append(meta.Parents, value)
|
||||||
|
|
||||||
case HeaderSpace:
|
case HeaderSpace:
|
||||||
meta.Space = strings.ToUpper(matches[2])
|
meta.Space = strings.ToUpper(value)
|
||||||
|
|
||||||
case HeaderTitle:
|
case HeaderTitle:
|
||||||
meta.Title = strings.TrimSpace(matches[2])
|
meta.Title = strings.TrimSpace(value)
|
||||||
|
|
||||||
case HeaderLayout:
|
case HeaderLayout:
|
||||||
meta.Layout = strings.TrimSpace(matches[2])
|
meta.Layout = strings.TrimSpace(value)
|
||||||
|
|
||||||
|
case HeaderAttachment:
|
||||||
|
meta.Attachments = append(meta.Attachments, value)
|
||||||
|
|
||||||
default:
|
default:
|
||||||
logger.Errorf(
|
log.Errorf(
|
||||||
`encountered unknown header '%s' line: %#v`,
|
nil,
|
||||||
|
`encountered unknown header %q line: %#v`,
|
||||||
header,
|
header,
|
||||||
line,
|
line,
|
||||||
)
|
)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user