From ada6f828ffe546c2c8995547c3c1846f587913e8 Mon Sep 17 00:00:00 2001 From: Egor Kovetskiy Date: Mon, 8 Apr 2019 22:44:27 +0300 Subject: [PATCH] separate mark into packages --- main.go | 174 +++++--------------------------- api.go => pkg/confluence/api.go | 36 +++++-- pkg/mark/ancestry.go | 120 ++++++++++++++++++++++ pkg/mark/mark.go | 90 +++++++++++++++++ meta.go => pkg/mark/meta.go | 4 +- 5 files changed, 265 insertions(+), 159 deletions(-) rename api.go => pkg/confluence/api.go (88%) create mode 100644 pkg/mark/ancestry.go create mode 100644 pkg/mark/mark.go rename meta.go => pkg/mark/meta.go (95%) diff --git a/main.go b/main.go index 8c93333..d197327 100644 --- a/main.go +++ b/main.go @@ -11,8 +11,10 @@ import ( "github.com/BurntSushi/toml" "github.com/kovetskiy/godocs" "github.com/kovetskiy/lorg" + "github.com/kovetskiy/mark/pkg/confluence" + "github.com/kovetskiy/mark/pkg/mark" "github.com/reconquest/colorgful" - "github.com/reconquest/ser-go" + "github.com/reconquest/karma-go" "github.com/russross/blackfriday" "github.com/zazab/zhash" ) @@ -87,24 +89,6 @@ Options: ` ) -type PageInfo struct { - ID string `json:"id"` - Title string `json:"title"` - - Version struct { - Number int64 `json:"number"` - } `json:"version"` - - Ancestors []struct { - Id string `json:"id"` - Title string `json:"title"` - } `json:"ancestors"` - - Links struct { - Full string `json:"webui"` - } `json:"_links"` -} - var ( logger = lorg.NewLog() ) @@ -151,7 +135,7 @@ func main() { logger.Fatal(err) } - meta, err := extractMeta(markdownData) + meta, err := mark.ExtractMeta(markdownData) if err != nil { logger.Fatal(err) } @@ -168,7 +152,7 @@ func main() { logger.Fatal(err) } - api := NewAPI(creds.BaseURL, creds.Username, creds.Password) + api := confluence.NewAPI(creds.BaseURL, creds.Username, creds.Password) if creds.PageID != "" && meta != nil { logger.Warningf( @@ -187,7 +171,7 @@ func main() { ) } - var target *PageInfo + var target *confluence.PageInfo if meta != nil { page, err := resolvePage(api, meta) @@ -201,7 +185,7 @@ func main() { logger.Fatalf("URL should provide 'pageId' GET-parameter") } - page, err := api.getPageByID(creds.PageID) + page, err := api.GetPageByID(creds.PageID) if err != nil { logger.Fatal(err) } @@ -209,7 +193,7 @@ func main() { target = page } - err = api.updatePage( + err = api.UpdatePage( target, MacroLayout{meta.Layout, [][]byte{htmlData}}.Render(), ) @@ -224,9 +208,13 @@ func main() { creds.Username, ) - err := api.setPagePermissions(target, RestrictionEdit, []Restriction{ - {User: creds.Username}, - }) + err := api.SetPagePermissions( + target, + confluence.RestrictionEdit, + []confluence.Restriction{ + {User: creds.Username}, + }, + ) if err != nil { logger.Fatal(err) } @@ -284,10 +272,13 @@ func compileMarkdown(markdown []byte) []byte { return html } -func resolvePage(api *API, meta *Meta) (*PageInfo, error) { - page, err := api.findPage(meta.Space, meta.Title) +func resolvePage( + api *confluence.API, + meta *mark.Meta, +) (*confluence.PageInfo, error) { + page, err := api.FindPage(meta.Space, meta.Title) if err != nil { - return nil, ser.Errorf( + return nil, karma.Format( err, "error during finding page '%s': %s", meta.Title, @@ -300,7 +291,7 @@ func resolvePage(api *API, meta *Meta) (*PageInfo, error) { } if len(ancestry) > 0 { - page, err := validateAncestry( + page, err := mark.ValidateAncestry( api, meta.Space, ancestry, @@ -325,13 +316,13 @@ func resolvePage(api *API, meta *Meta) (*PageInfo, error) { ) } - parent, err := ensureAncestry( + parent, err := mark.EnsureAncestry( api, meta.Space, meta.Parents, ) if err != nil { - return nil, ser.Errorf( + return nil, karma.Format( err, "can't create ancestry tree: %s; error: %s", strings.Join(meta.Parents, ` > `), @@ -352,9 +343,9 @@ func resolvePage(api *API, meta *Meta) (*PageInfo, error) { ) if page == nil { - page, err := api.createPage(meta.Space, parent, meta.Title, ``) + page, err := api.CreatePage(meta.Space, parent, meta.Title, ``) if err != nil { - return nil, ser.Errorf( + return nil, karma.Format( err, "can't create page '%s': %s", meta.Title, @@ -367,117 +358,6 @@ func resolvePage(api *API, meta *Meta) (*PageInfo, error) { return page, nil } -func ensureAncestry( - api *API, - space string, - ancestry []string, -) (*PageInfo, error) { - var parent *PageInfo - - rest := ancestry - - for i, title := range ancestry { - page, err := api.findPage(space, title) - if err != nil { - return nil, ser.Errorf( - err, - `error during finding parent page with title '%s': %s`, - title, - ) - } - - if page == nil { - break - } - - logger.Tracef("parent page '%s' exists: %s", title, page.Links.Full) - - rest = ancestry[i:] - parent = page - } - - if parent != nil { - rest = rest[1:] - } else { - page, err := api.findRootPage(space) - if err != nil { - return nil, ser.Errorf( - err, - "can't find root page for space '%s': %s", space, - ) - } - - parent = page - } - - if len(rest) == 0 { - return parent, nil - } - - logger.Debugf( - "empty pages under '%s' to be created: %s", - parent.Title, - strings.Join(rest, ` > `), - ) - - for _, title := range rest { - page, err := api.createPage(space, parent, title, ``) - if err != nil { - return nil, ser.Errorf( - err, - `error during creating parent page with title '%s': %s`, - title, - ) - } - - parent = page - } - - return parent, nil -} - -func validateAncestry( - api *API, - space string, - ancestry []string, -) (*PageInfo, error) { - page, err := api.findPage(space, ancestry[len(ancestry)-1]) - if err != nil { - return nil, err - } - - if page == nil { - return nil, nil - } - - if len(page.Ancestors) < 1 { - return nil, fmt.Errorf(`page '%s' has no parents`, page.Title) - } - - if len(page.Ancestors) < len(ancestry) { - return nil, fmt.Errorf( - "page '%s' has fewer parents than specified: %s", - page.Title, - strings.Join(ancestry, ` > `), - ) - } - - // skipping root article title - for i, ancestor := range page.Ancestors[1:len(ancestry)] { - if ancestor.Title != ancestry[i] { - return nil, fmt.Errorf( - "broken ancestry tree; expected tree: %s; "+ - "encountered '%s' at position of '%s'", - strings.Join(ancestry, ` > `), - ancestor.Title, - ancestry[i], - ) - } - } - - return page, nil -} - func getConfig(path string) (zhash.Hash, error) { configData := map[string]interface{}{} _, err := toml.DecodeFile(path, &configData) @@ -486,7 +366,7 @@ func getConfig(path string) (zhash.Hash, error) { return zhash.NewHash(), err } - return zhash.NewHash(), ser.Errorf( + return zhash.NewHash(), karma.Format( err, "can't decode toml file: %s", ) diff --git a/api.go b/pkg/confluence/api.go similarity index 88% rename from api.go rename to pkg/confluence/api.go index 8709074..61ffc16 100644 --- a/api.go +++ b/pkg/confluence/api.go @@ -1,4 +1,4 @@ -package main +package confluence import ( "fmt" @@ -27,6 +27,24 @@ type API struct { json *gopencils.Resource } +type PageInfo struct { + ID string `json:"id"` + Title string `json:"title"` + + Version struct { + Number int64 `json:"number"` + } `json:"version"` + + Ancestors []struct { + Id string `json:"id"` + Title string `json:"title"` + } `json:"ancestors"` + + Links struct { + Full string `json:"webui"` + } `json:"_links"` +} + func NewAPI(baseURL string, username string, password string) *API { auth := &gopencils.BasicAuth{username, password} @@ -40,8 +58,8 @@ func NewAPI(baseURL string, username string, password string) *API { } } -func (api *API) findRootPage(space string) (*PageInfo, error) { - page, err := api.findPage(space, ``) +func (api *API) FindRootPage(space string) (*PageInfo, error) { + page, err := api.FindPage(space, ``) if err != nil { return nil, fmt.Errorf( `can't obtain first page from space '%s': %s`, @@ -64,8 +82,7 @@ func (api *API) findRootPage(space string) (*PageInfo, error) { }, nil } -func (api *API) findPage(space string, title string) (*PageInfo, error) { - +func (api *API) FindPage(space string, title string) (*PageInfo, error) { result := struct { Results []PageInfo `json:"results"` }{} @@ -105,8 +122,7 @@ func (api *API) findPage(space string, title string) (*PageInfo, error) { return &result.Results[0], nil } -func (api *API) getPageByID(pageID string) (*PageInfo, error) { - +func (api *API) GetPageByID(pageID string) (*PageInfo, error) { request, err := api.rest.Res( "content/"+pageID, &PageInfo{}, ).Get(map[string]string{"expand": "ancestors,version"}) @@ -136,7 +152,7 @@ func (api *API) getPageByID(pageID string) (*PageInfo, error) { return request.Response.(*PageInfo), nil } -func (api *API) createPage( +func (api *API) CreatePage( space string, parent *PageInfo, title string, @@ -183,7 +199,7 @@ func (api *API) createPage( return request.Response.(*PageInfo), nil } -func (api *API) updatePage( +func (api *API) UpdatePage( page *PageInfo, newContent string, ) error { nextPageVersion := page.Version.Number + 1 @@ -238,7 +254,7 @@ func (api *API) updatePage( return nil } -func (api *API) setPagePermissions( +func (api *API) SetPagePermissions( page *PageInfo, operation RestrictionOperation, restrictions []Restriction, diff --git a/pkg/mark/ancestry.go b/pkg/mark/ancestry.go new file mode 100644 index 0000000..2136e4f --- /dev/null +++ b/pkg/mark/ancestry.go @@ -0,0 +1,120 @@ +package mark + +import ( + "fmt" + "strings" + + "github.com/kovetskiy/mark/pkg/confluence" + "github.com/reconquest/karma-go" +) + +func EnsureAncestry( + api *confluence.API, + space string, + ancestry []string, +) (*confluence.PageInfo, error) { + var parent *confluence.PageInfo + + rest := ancestry + + for i, title := range ancestry { + page, err := api.FindPage(space, title) + if err != nil { + return nil, karma.Format( + err, + `error during finding parent page with title '%s': %s`, + title, + ) + } + + if page == nil { + break + } + + logger.Tracef("parent page '%s' exists: %s", title, page.Links.Full) + + rest = ancestry[i:] + parent = page + } + + if parent != nil { + rest = rest[1:] + } else { + page, err := api.FindRootPage(space) + if err != nil { + return nil, karma.Format( + err, + "can't find root page for space '%s': %s", space, + ) + } + + parent = page + } + + if len(rest) == 0 { + return parent, nil + } + + logger.Debugf( + "empty pages under '%s' to be created: %s", + parent.Title, + strings.Join(rest, ` > `), + ) + + for _, title := range rest { + page, err := api.CreatePage(space, parent, title, ``) + if err != nil { + return nil, karma.Format( + err, + `error during creating parent page with title '%s': %s`, + title, + ) + } + + parent = page + } + + return parent, nil +} + +func ValidateAncestry( + api *confluence.API, + space string, + ancestry []string, +) (*confluence.PageInfo, error) { + page, err := api.FindPage(space, ancestry[len(ancestry)-1]) + if err != nil { + return nil, err + } + + if page == nil { + return nil, nil + } + + if len(page.Ancestors) < 1 { + return nil, fmt.Errorf(`page '%s' has no parents`, page.Title) + } + + if len(page.Ancestors) < len(ancestry) { + return nil, fmt.Errorf( + "page '%s' has fewer parents than specified: %s", + page.Title, + strings.Join(ancestry, ` > `), + ) + } + + // skipping root article title + for i, ancestor := range page.Ancestors[1:len(ancestry)] { + if ancestor.Title != ancestry[i] { + return nil, fmt.Errorf( + "broken ancestry tree; expected tree: %s; "+ + "encountered '%s' at position of '%s'", + strings.Join(ancestry, ` > `), + ancestor.Title, + ancestry[i], + ) + } + } + + return page, nil +} diff --git a/pkg/mark/mark.go b/pkg/mark/mark.go new file mode 100644 index 0000000..ad4277c --- /dev/null +++ b/pkg/mark/mark.go @@ -0,0 +1,90 @@ +package mark + +import ( + "strings" + + "github.com/kovetskiy/lorg" + "github.com/kovetskiy/mark/pkg/confluence" + "github.com/reconquest/karma-go" +) + +var ( + logger lorg.Logger = lorg.NewDiscarder() +) + +func SetLogger(log lorg.Logger) { + logger = log +} + +func ResolvePage( + api *confluence.API, + meta *Meta, +) (*confluence.PageInfo, error) { + page, err := api.FindPage(meta.Space, meta.Title) + if err != nil { + return nil, karma.Format( + err, + "error during finding page '%s': %s", + meta.Title, + ) + } + + ancestry := meta.Parents + if page != nil { + ancestry = append(ancestry, page.Title) + } + + if len(ancestry) > 0 { + page, err := ValidateAncestry( + api, + meta.Space, + ancestry, + ) + if err != nil { + return nil, err + } + + if page == nil { + logger.Warningf( + "page '%s' is not found ", + meta.Parents[len(ancestry)-1], + ) + } + + path := meta.Parents + path = append(path, meta.Title) + + logger.Debugf( + "resolving page path: ??? > %s", + strings.Join(path, ` > `), + ) + } + + parent, err := EnsureAncestry( + api, + meta.Space, + meta.Parents, + ) + if err != nil { + return nil, karma.Format( + err, + "can't create ancestry tree: %s; error: %s", + strings.Join(meta.Parents, ` > `), + ) + } + + titles := []string{} + for _, page := range parent.Ancestors { + titles = append(titles, page.Title) + } + + titles = append(titles, parent.Title) + + logger.Infof( + "page will be stored under path: %s > %s", + strings.Join(titles, ` > `), + meta.Title, + ) + + return page, nil +} diff --git a/meta.go b/pkg/mark/meta.go similarity index 95% rename from meta.go rename to pkg/mark/meta.go index d7c446a..b4986fd 100644 --- a/meta.go +++ b/pkg/mark/meta.go @@ -1,4 +1,4 @@ -package main +package mark import ( "bufio" @@ -22,7 +22,7 @@ type Meta struct { Layout string } -func extractMeta(data []byte) (*Meta, error) { +func ExtractMeta(data []byte) (*Meta, error) { headerPattern := regexp.MustCompile(`\[\]:\s*#\s*\(([^:]+):\s*(.*)\)`) var meta *Meta