Mercurial > hg > Members > anatofuz > growsync
changeset 5:af840bc25791
impl edit cmd
author | anatofuz <anatofuz@cr.ie.u-ryukyu.ac.jp> |
---|---|
date | Fri, 04 Dec 2020 18:27:09 +0900 |
parents | 359eff175bf1 |
children | 0b9932242273 |
files | client.go client/client.go client/page.go cmd_edit.go cmd_new.go cmd_push.go config.go editor.go go.mod go.sum growsync.go util.go |
diffstat | 12 files changed, 404 insertions(+), 82 deletions(-) [+] |
line wrap: on
line diff
--- a/client.go Tue Dec 01 21:37:47 2020 +0900 +++ b/client.go Fri Dec 04 18:27:09 2020 +0900 @@ -2,17 +2,18 @@ import ( "context" + "fmt" "io/ioutil" - "github.com/crowi/go-crowi" + "www.cr.ie.u-ryukyu.ac.jp/hg/Members/anatofuz/growsync/client" ) type growClient struct { - client *crowi.Client + client *client.Client } func NewGrowiClient(url, token string) (*growClient, error) { - client, err := crowi.NewClient(crowi.Config{URL: url, Token: token}) + client, err := client.NewClient(client.Config{URL: url, Token: token}) if err != nil { return nil, err } @@ -22,13 +23,17 @@ return &gClient, nil } -func (gClient *growClient) CheckIsExistsToken(path string) (bool, error) { +func (gClient *growClient) IsExistsPageOnGrowi(path string) (*client.Page, error) { ctx := context.Background() page, err := gClient.client.Pages.Get(ctx, path) + + if err == client.ErrorPageNotFOund { + return nil, nil + } if err != nil { - return false, err + return nil, err } - return page.OK, nil + return page, nil } func (gClient *growClient) CreateNewPage(path string, mdPATH string) error { @@ -47,6 +52,18 @@ if err != nil { return err } - _, err = gClient.client.Pages.Update(ctx, path, string(markdown)) + + page, err := gClient.IsExistsPageOnGrowi(path) + + if err != nil { + return err + } + + if page == nil { + fmt.Println("[info] create new page", mdPATH) + return gClient.CreateNewPage(path, mdPATH) + } + + _, err = gClient.client.Pages.Update(ctx, page.ID, page.Revision.ID, string(markdown)) return err }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/client/client.go Fri Dec 04 18:27:09 2020 +0900 @@ -0,0 +1,97 @@ +package client + +import ( + "context" + "fmt" + "io" + "io/ioutil" + "net/http" + "net/url" + "path" + "strings" +) + +type ID string + +type Config struct { + URL string + Token string +} + +type Client struct { + httpClient *http.Client + config *Config + + Pages *PagesService +} + +type service struct { + client *Client +} + +func NewClient(cfg Config) (*Client, error) { + if cfg.URL == "" { + return nil, fmt.Errorf("missing growi url") + } + + if cfg.Token == "" { + return nil, fmt.Errorf("missing api token") + } + + httpClient := http.DefaultClient + + client := Client{ + httpClient: httpClient, + config: &cfg, + } + client.Pages = &PagesService{client: &client} + return &client, nil +} + +func isMethod(method string) bool { + for _, httpMethod := range []string{http.MethodGet, http.MethodPost, http.MethodDelete, http.MethodPut} { + if method == httpMethod { + return true + } + } + return false +} + +func (c *Client) newRequest(ctx context.Context, method string, uri string, params *url.Values) ([]byte, error) { + if !isMethod(method) { + return nil, fmt.Errorf("failed not http metod %s", method) + } + + u, err := url.Parse(c.config.URL) + if err != nil { + return nil, err + } + + var body io.Reader + if method == http.MethodGet { + u.RawQuery = params.Encode() + } else { + body = strings.NewReader(params.Encode()) + } + + u.Path = path.Join(u.Path, uri) + + fmt.Printf("[info] method %s, url %s body %s\n", method, u.String(), body) + req, err := http.NewRequest(method, u.String(), body) + req = req.WithContext(ctx) + + if params != nil { + req.Header.Set("Content-Type", "application/x-www-form-urlencoded") + } + + resp, err := c.httpClient.Do(req) + if err != nil { + return nil, err + } + defer resp.Body.Close() + content, err := ioutil.ReadAll(resp.Body) + if err != nil { + return nil, err + } + return content, nil +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/client/page.go Fri Dec 04 18:27:09 2020 +0900 @@ -0,0 +1,152 @@ +package client + +import ( + "context" + "encoding/json" + "fmt" + "net/http" + "net/url" + "time" +) + +type PagesService service + +type User struct { + IsGravatarEnabled bool `json:"isGravatarEnabled"` + IsEmailPublished bool `json:"isEmailPublished"` + Lang string `json:"lang"` + Status int `json:"status"` + Admin bool `json:"admin"` + ID string `json:"_id"` + CreatedAt time.Time `json:"createdAt"` + Name string `json:"name"` + Username string `json:"username"` + Email string `json:"email"` + LastLoginAt time.Time `json:"lastLoginAt"` + ImageURLCached string `json:"imageUrlCached"` +} + +type Revision struct { + Format string `json:"format"` + ID string `json:"_id"` + CreatedAt time.Time `json:"createdAt"` + Path string `json:"path"` + Body string `json:"body"` + Author User `json:"author"` + HasDiffToPrev bool `json:"hasDiffToPrev"` + V int `json:"__v"` +} + +type Page struct { + Status string `json:"status"` + Grant int `json:"grant"` + GrantedUsers []interface{} `json:"grantedUsers"` + Liker []interface{} `json:"liker"` + SeenUsers []string `json:"seenUsers"` + CommentCount int `json:"commentCount"` + Extended string `json:"extended"` + SubID string `json:"_id"` + CreatedAt time.Time `json:"createdAt"` + UpdatedAt time.Time `json:"updatedAt"` + Path string `json:"path"` + Creator User `json:"creator"` + LastUpdateUser User `json:"lastUpdateUser"` + RedirectTo interface{} `json:"redirectTo"` + GrantedGroup interface{} `json:"grantedGroup"` + V int `json:"__v"` + ID string `json:"id"` + Revision Revision `json:"revision"` +} + +type PagesGet struct { + Page Page `json:"page"` + Ok bool `json:"ok"` + Error string `json:"error"` +} + +type PagesCreate struct { + Page Page `json:"page"` + Ok bool `json:"ok"` + Revision Revision `json:"revision"` + Error string `json:"error"` +} + +type UpdateParams struct { + PageID string + RevisionID string +} + +var ErrorPageNotFOund = fmt.Errorf("page not found") + +const CREATE_ENDPOINT string = "/_api/pages.create" + +// Create makes a page in your Crowi. The request requires +// the path and page content used for the page name +func (p *PagesService) Create(ctx context.Context, path, body string) (*PagesCreate, error) { + fmt.Printf("path %s, body %s\n", path, body) + params := url.Values{} + params.Add("access_token", p.client.config.Token) + params.Add("path", path) + params.Add("body", body) + res, err := p.client.newRequest(ctx, http.MethodPost, CREATE_ENDPOINT, ¶ms) + if err != nil { + fmt.Println("[error] failed send client request") + fmt.Println(string(res)) + return nil, err + } + + createPages := PagesCreate{} + if err := json.Unmarshal(res, &createPages); err != nil { + fmt.Println("[error] failed unmarshal json resupons") + fmt.Println(string(res)) + return nil, err + } + + return &createPages, nil +} + +const GET_ENDPOINT string = "/_api/pages.get" + +func (p *PagesService) Get(ctx context.Context, path string) (*Page, error) { + params := url.Values{} + params.Add("access_token", p.client.config.Token) + params.Add("path", path) + + res, err := p.client.newRequest(ctx, http.MethodGet, GET_ENDPOINT, ¶ms) + if err != nil { + return nil, err + } + pagesGet := PagesGet{} + if err := json.Unmarshal(res, &pagesGet); err != nil { + return nil, err + } + + if !pagesGet.Ok { + return nil, ErrorPageNotFOund + } + + return &pagesGet.Page, nil +} + +const UPDATE_ENDPOINT string = "/_api/pages.update" + +func (p *PagesService) Update(ctx context.Context, pageID, revisionID, body string) (*Page, error) { + params := url.Values{} + params.Add("access_token", p.client.config.Token) + params.Add("page_id", pageID) + params.Add("revision_id", revisionID) + params.Add("body", body) + + res, err := p.client.newRequest(ctx, http.MethodPost, UPDATE_ENDPOINT, ¶ms) + if err != nil { + return nil, err + } + page := Page{} + if err := json.Unmarshal(res, &page); err != nil { + fmt.Println("[error] failed unmarshal json resupons") + fmt.Println(string(res)) + return nil, err + } + + return &page, nil +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cmd_edit.go Fri Dec 04 18:27:09 2020 +0900 @@ -0,0 +1,58 @@ +package growsync + +import ( + "context" + "flag" + "fmt" + "io" + "path/filepath" + "time" +) + +type editCmd struct{} + +const layout string = "2006/01/02" + +func (pc *editCmd) name() string { + return "edit" +} + +func (pc *editCmd) description() string { + return "edit from growi web app" +} + +func (pc *editCmd) run(ctx context.Context, argv []string, config *growiConfig, stdWriter io.Writer, errorWriter io.Writer) error { + fs := flag.NewFlagSet("growsync edit", flag.ContinueOnError) + fs.SetOutput(errorWriter) + + if err := fs.Parse(argv); err != nil { + return nil + } + + var growiPATH string + + if fs.NArg() < 1 { + growiPATH = createNewDailyMarkdownPATH(config.DailyPATH) + } else { + growiPATH = convertGrowiSystemPath(fs.Arg(0)) + } + + localFilePATH := filepath.Join(config.LocalRoot, growiPATH+".md") + + client, err := NewGrowiClient(config.URL, config.TOKEN) + if err != nil { + return err + } + + err = doEdit(localFilePATH) + if err != nil { + return fmt.Errorf("failed edit mardkwodn file %+v", err) + } + + return client.UpdatePage(growiPATH, localFilePATH) +} + +func createNewDailyMarkdownPATH(dailyPATH string) string { + now := time.Now() + return filepath.Join(dailyPATH, now.Format(layout)) +}
--- a/cmd_new.go Tue Dec 01 21:37:47 2020 +0900 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,52 +0,0 @@ -package growsync - -import ( - "context" - "flag" - "fmt" - "io" - "path/filepath" - "time" -) - -type newCmd struct{} - -const layout string = "2006/01/02" - -func (pc *newCmd) name() string { - return "new" -} - -func (pc *newCmd) description() string { - return "new from growi web app" -} - -func (pc *newCmd) run(ctx context.Context, argv []string, config *growiConfig, stdWriter io.Writer, errorWriter io.Writer) error { - fs := flag.NewFlagSet("growsync new", flag.ContinueOnError) - fs.SetOutput(errorWriter) - - if err := fs.Parse(argv); err != nil { - return nil - } - - var newMarkdownPATH string - - if fs.NArg() < 1 { - newMarkdownPATH = createNewDailyMarkdownPATH(config.DailyPATH) - } else { - newMarkdownPATH = fs.Arg(0) - } - - _, err := NewGrowiClient(config.URL, config.TOKEN) - if err != nil { - return err - } - - fmt.Println(newMarkdownPATH) - return nil -} - -func createNewDailyMarkdownPATH(dailyPATH string) string { - now := time.Now() - return filepath.Join(dailyPATH, now.Format(layout)) -}
--- a/cmd_push.go Tue Dec 01 21:37:47 2020 +0900 +++ b/cmd_push.go Fri Dec 04 18:27:09 2020 +0900 @@ -3,7 +3,6 @@ import ( "context" "flag" - "fmt" "io" "golang.org/x/xerrors" @@ -38,12 +37,15 @@ markdownPATH := fs.Arg(0) growiSystemPath := convertGrowiSystemPath(markdownPATH) - isExists, err := client.CheckIsExistsToken(growiSystemPath) - fmt.Println(isExists) + id, err := client.IsExistsPageOnGrowi(growiSystemPath) - if isExists { - return client.UpdatePage(growiSystemPath, markdownPATH) + if err != nil { + return err } - return client.CreateNewPage(growiSystemPath, markdownPATH) + if id == nil { + return client.CreateNewPage(growiSystemPath, markdownPATH) + } + + return client.UpdatePage(growiSystemPath, markdownPATH) }
--- a/config.go Tue Dec 01 21:37:47 2020 +0900 +++ b/config.go Fri Dec 04 18:27:09 2020 +0900 @@ -37,16 +37,8 @@ return "", err } configFilePATH := filepath.Join(home, ".config", "growsync", "config.yaml") - if !fileCheck(configFilePATH) { + if !existsFile(configFilePATH) { return "", fmt.Errorf("[ERROR] conf file not found") } return configFilePATH, nil } - -func fileCheck(conf string) bool { - info, err := os.Stat(conf) - if os.IsNotExist(err) { - return false - } - return !info.IsDir() -}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/editor.go Fri Dec 04 18:27:09 2020 +0900 @@ -0,0 +1,31 @@ +package growsync + +import ( + "os" + "os/exec" + "strings" + + "github.com/mattn/go-tty" +) + +func doEdit(mdfilePATH string) error { + editor := os.Getenv("EDITOR") + if editor == "" { + editor = "vi" + } + tty, err := tty.Open() + if err != nil { + return err + } + defer tty.Close() + + editorWithArgs := strings.Fields(editor) + editorWithArgs = append(editorWithArgs, mdfilePATH) + + cmd := exec.Command(editorWithArgs[0], editorWithArgs[1:]...) + cmd.Stdin = tty.Input() + cmd.Stdout = tty.Output() + cmd.Stderr = tty.Output() + + return cmd.Run() +}
--- a/go.mod Tue Dec 01 21:37:47 2020 +0900 +++ b/go.mod Fri Dec 04 18:27:09 2020 +0900 @@ -3,9 +3,9 @@ go 1.15 require ( - github.com/crowi/go-crowi v0.0.0-20170809061107-ef04e39ae1ac github.com/goccy/go-yaml v1.8.4 + github.com/mattn/go-tty v0.0.3 github.com/pkg/errors v0.9.1 - golang.org/x/net v0.0.0-20201110031124-69a78807bb2b // indirect + golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f // indirect golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 )
--- a/go.sum Tue Dec 01 21:37:47 2020 +0900 +++ b/go.sum Fri Dec 04 18:27:09 2020 +0900 @@ -1,40 +1,56 @@ -github.com/crowi/go-crowi v0.0.0-20170809061107-ef04e39ae1ac h1:52GTmB0wFiTZTKBG/n1g84xum2dL5lkhN1gXtY3xRSo= -github.com/crowi/go-crowi v0.0.0-20170809061107-ef04e39ae1ac/go.mod h1:fHmF2Li4ysI3D5EXN3eUO4FEEumXn+S6DUrl/F6Gxlg= +github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/fatih/color v1.10.0 h1:s36xzo75JdqLaaWoiEHk767eHiwo0598uUxyfiPkDsg= github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM= +github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A= github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= +github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q= github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= +github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no= github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= +github.com/go-playground/validator/v10 v10.4.1 h1:pH2c5ADXtd66mxoE0Zm9SUhxE20r7aM3F26W0hOn+GE= github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4= github.com/goccy/go-yaml v1.8.4 h1:AOEdR7aQgbgwHznGe3BLkDQVujxCPUpHOZZcQcp8Y3M= github.com/goccy/go-yaml v1.8.4/go.mod h1:U/jl18uSupI5rdI2jmuCswEA2htH9eXfferR3KfscvA= +github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y= github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= +github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ0s8= github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-runewidth v0.0.6/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= +github.com/mattn/go-tty v0.0.3 h1:5OfyWorkyO7xP52Mq7tB36ajHDG5OHrmBGIS/DtakQI= +github.com/mattn/go-tty v0.0.3/go.mod h1:ihxohKRERHTVzN+aSVRwACLCeqIoZAWpoICkkvrWyR0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20201110031124-69a78807bb2b h1:uwuIcX0g4Yl1NC5XAz37xsr2lTtcqevgzYNVt49waME= -golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f h1:+Nyd8tzPX9R7BWHguqsrbFdRx3WQ/1ib8I44HXV5yTA= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= -golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
--- a/growsync.go Tue Dec 01 21:37:47 2020 +0900 +++ b/growsync.go Fri Dec 04 18:27:09 2020 +0900 @@ -13,7 +13,7 @@ const cmdName = "growsync" var ( - subCommands = []cmd{&newCmd{}, &pushCmd{}, &rootCmd{}, &versionCmd{}} + subCommands = []cmd{&editCmd{}, &pushCmd{}, &rootCmd{}, &versionCmd{}} dispatch = make(map[string]cmd, len(subCommands)) maxSubcommandName int )
--- a/util.go Tue Dec 01 21:37:47 2020 +0900 +++ b/util.go Fri Dec 04 18:27:09 2020 +0900 @@ -1,6 +1,7 @@ package growsync import ( + "os" "path/filepath" "strings" ) @@ -23,3 +24,11 @@ return outputPATH } + +func existsFile(conf string) bool { + info, err := os.Stat(conf) + if os.IsNotExist(err) { + return false + } + return !info.IsDir() +}