Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ default:
- `$local_root/$blogID/` 配下にエントリが格納されます。`omit_domain` 設定がされている場合はブログIDは含まれず、local\_root直下にエントリーが格納されます
- `<blog>.omit_domain`: ブログエントリを格納するパスにブログIDを含めません。
- `<blog>.owner`: 編集対象のブログオーナーが自身とは別のユーザーの場合、ブログオーナーを個別に設定できます。
- `<blog>.entry_directory`: ブログエントリを格納するディレクトリ名を指定します。デフォルトは「/entry/」です。はてなブログで記事を配信するディレクトリを変更している場合に設定します。

#### ブログオーナーが自身とは別の場合の設定

Expand All @@ -67,6 +68,17 @@ example.hatenablog.com:
owner: <OWNER>
```

#### 記事配信ディレクトリを変更している場合の設定

はてなブログの設定で記事配信ディレクトリを変更している場合は、以下のように設定します。

```yaml
example.hatenablog.com:
username: sample
password: <API KEY>
entry_directory: articles
```

### エントリをダウンロードする(blogsync pull)

設定が完了したら、以下のコマンドを実行すると当該のブログに投稿しているエントリがその URL ローカルに保存されます。固定ページ機能を利用している場合、それもまとめてダウンロードされます。
Expand Down
8 changes: 4 additions & 4 deletions broker.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ func (b *broker) LocalPath(e *entry) string {
localPath := e.URL.Path

if e.IsDraft && e.isBlogEntry() {
subdir, entryPath := extractEntryPath(e.URL.Path)
subdir, entryPath := b.blogConfig.extractEntryPath(e.URL.Path)
if entryPath == "" {
return ""
}
Expand All @@ -108,7 +108,7 @@ func (b *broker) LocalPath(e *entry) string {
// https://blog.hatena.ne.jp/Songmu/songmu.hatenadiary.org/atom/entry/6801883189050452361
paths := strings.Split(e.EditURL, "/")
if len(paths) == 8 {
localPath = subdir + "/entry/" + draftDir + paths[7] // path[7] is entryID
localPath = subdir + b.blogConfig.entryDirectory() + draftDir + paths[7] // path[7] is entryID
}
}
}
Expand All @@ -133,7 +133,7 @@ func (b *broker) Store(e *entry, path, origPath string) error {
logf("store", "%s", path)

if e.IsDraft && e.isBlogEntry() {
_, entryPath := extractEntryPath(e.URL.Path)
_, entryPath := b.blogConfig.extractEntryPath(e.URL.Path)
if entryPath == "" {
return fmt.Errorf("invalid path: %s", e.URL.Path)
}
Expand Down Expand Up @@ -224,4 +224,4 @@ func entryEndPointUrl(bc *blogConfig) string {

func staticPageEndpointURL(bc *blogConfig) string {
return atomEndpointURLRoot(bc) + "page"
}
}
39 changes: 31 additions & 8 deletions config.go
Original file line number Diff line number Diff line change
Expand Up @@ -101,14 +101,15 @@ func (c *config) localBlogIDs() []string {
}

type blogConfig struct {
BlogID string `yaml:"-"`
LocalRoot string `yaml:"local_root"`
Username string
Password string
OmitDomain *bool `yaml:"omit_domain"`
Owner string `yaml:"owner"`
local bool
rootURL string
BlogID string `yaml:"-"`
LocalRoot string `yaml:"local_root"`
Username string
Password string
OmitDomain *bool `yaml:"omit_domain"`
Owner string `yaml:"owner"`
EntryDirectory *string `yaml:"entry_directory"`
local bool
rootURL string
}

func (bc *blogConfig) localRoot() string {
Expand All @@ -119,6 +120,25 @@ func (bc *blogConfig) localRoot() string {
return filepath.Join(paths...)
}

func (bc *blogConfig) entryDirectory() string {
if bc.EntryDirectory == nil {
return "/entry/"
}

if *bc.EntryDirectory == "" {
return ""
}

dir := *bc.EntryDirectory
if !strings.HasPrefix(dir, "/") {
dir = "/" + dir
}
if !strings.HasSuffix(dir, "/") {
dir = dir + "/"
}
return dir
}

func (bc *blogConfig) fetchRootURL() string {
if bc.rootURL != "" {
return bc.rootURL
Expand Down Expand Up @@ -230,6 +250,9 @@ func mergeBlogConfig(b1, b2 *blogConfig) *blogConfig {
if b1.OmitDomain == nil {
b1.OmitDomain = b2.OmitDomain
}
if b1.EntryDirectory == nil {
b1.EntryDirectory = b2.EntryDirectory
}
if !b1.local {
b1.local = b2.local
}
Expand Down
55 changes: 55 additions & 0 deletions config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -355,3 +355,58 @@ func TestLoadConfigration(t *testing.T) {
})
}
}

func TestEntryDirectory(t *testing.T) {
testCases := []struct {
name string
entryDirectory *string
expectedDirectory string
local bool
blogID string
}{
{
name: "default directory",
entryDirectory: nil,
expectedDirectory: "/entry/",
},
{
name: "custom directory",
entryDirectory: pstr("articles"),
expectedDirectory: "/articles/",
},
{
name: "directory with leading slash",
entryDirectory: pstr("/articles"),
expectedDirectory: "/articles/",
},
{
name: "directory with trailing slash",
entryDirectory: pstr("articles/"),
expectedDirectory: "/articles/",
},
{
name: "directory with both slashes",
entryDirectory: pstr("/articles/"),
expectedDirectory: "/articles/",
},
{
name: "empty directory explicitly set in local config",
entryDirectory: pstr(""),
expectedDirectory: "",
},
}

for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
bc := &blogConfig{
EntryDirectory: tc.entryDirectory,
local: tc.local,
BlogID: tc.blogID,
}
dir := bc.entryDirectory()
if dir != tc.expectedDirectory {
t.Errorf("entryDirectory: got %#v, want %#v", dir, tc.expectedDirectory)
}
})
}
}
10 changes: 8 additions & 2 deletions entry.go
Original file line number Diff line number Diff line change
Expand Up @@ -303,8 +303,14 @@ func modTime(fpath string) (time.Time, error) {
return ti, nil
}

func extractEntryPath(p string) (subdir string, entryPath string) {
stuffs := strings.SplitN(p, "/entry/", 2)
func (bc *blogConfig) extractEntryPath(p string) (subdir string, entryPath string) {
entryDir := bc.entryDirectory()
if entryDir == "" {
entryPath = strings.TrimSuffix(p, entryExt)
return "", entryPath
}

stuffs := strings.SplitN(p, entryDir, 2)
if len(stuffs) != 2 {
return "", ""
}
Expand Down
68 changes: 68 additions & 0 deletions entry_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,10 @@ func mustURLParse(s string) *url.URL {
return u
}

func pstr(s string) *string {
return &s
}

func TestFullContent(t *testing.T) {
testCases := []struct {
name string
Expand Down Expand Up @@ -192,3 +196,67 @@ foo bar カテゴリー
})
}
}

func TestExtractEntryPath(t *testing.T) {
testCases := []struct {
name string
path string
bc *blogConfig
subdir string
entryPath string
}{
{
name: "default entry directory",
path: "/path/to/entry/2012/12/18/post.md",
bc: nil,
subdir: "/path/to",
entryPath: "2012/12/18/post",
},
{
name: "custom entry directory",
path: "/path/to/articles/2012/12/18/post.md",
bc: &blogConfig{EntryDirectory: pstr("articles")},
subdir: "/path/to",
entryPath: "2012/12/18/post",
},
{
name: "with bc but default entry directory",
path: "/path/to/entry/2012/12/18/post.md",
bc: &blogConfig{EntryDirectory: nil},
subdir: "/path/to",
entryPath: "2012/12/18/post",
},
{
name: "invalid path",
path: "/path/to/invalid/path.md",
bc: nil,
subdir: "",
entryPath: "",
},
{
name: "empty directory",
path: "/path/to/2012/12/18/post.md",
bc: &blogConfig{EntryDirectory: pstr(""), local: true, BlogID: "blog.example.com"},
subdir: "",
entryPath: "/path/to/2012/12/18/post",
},
}

for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
var subdir, entryPath string
if tc.bc != nil {
subdir, entryPath = tc.bc.extractEntryPath(tc.path)
} else {
defaultBc := &blogConfig{}
subdir, entryPath = defaultBc.extractEntryPath(tc.path)
}
if subdir != tc.subdir {
t.Errorf("subdir: got %#v, want %#v", subdir, tc.subdir)
}
if entryPath != tc.entryPath {
t.Errorf("entryPath: got %#v, want %#v", entryPath, tc.entryPath)
}
})
}
}
6 changes: 3 additions & 3 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,7 @@ var commandPush = &cli.Command{
// relative position from the entry directory is obtained as a custom path as below.
blogPath, _ := filepath.Rel(bc.localRoot(), path)
blogPath = "/" + filepath.ToSlash(blogPath)
_, entryPath := extractEntryPath(path)
_, entryPath := bc.extractEntryPath(path)
if entryPath == "" {
return fmt.Errorf("%q is not a blog entry", path)
}
Expand All @@ -226,7 +226,7 @@ var commandPush = &cli.Command{
blogPath, _ := filepath.Rel(bc.localRoot(), path)
blogPath = "/" + filepath.ToSlash(blogPath)

if _, entryPath := extractEntryPath(path); entryPath != "" {
if _, entryPath := bc.extractEntryPath(path); entryPath != "" {
if !isLikelyGivenPath(entryPath) && !strings.HasPrefix(entryPath, draftDir) {
entry.CustomPath = entryPath
}
Expand Down Expand Up @@ -368,4 +368,4 @@ var commandRemove = &cli.Command{
}
return nil
},
}
}
5 changes: 3 additions & 2 deletions main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,8 @@ func TestBlogsync(t *testing.T) {
}
entryFile = publishedFile

_, entryPath := extractEntryPath(entryFile)
defaultBc := &blogConfig{}
_, entryPath := defaultBc.extractEntryPath(entryFile)
if !isLikelyGivenPath(entryPath) {
t.Errorf("unexpected published file: %s", entryFile)
}
Expand Down Expand Up @@ -278,4 +279,4 @@ func appendFile(path string, content string) error {
return err
}
return fh.Close()
}
}
Loading