Code Monkey home page Code Monkey logo

blogsync's Introduction

blogsync

Build Status MIT License PkgGoDev

Description

はてなBlog用のCLIクライアントです

Installation

% brew install Songmu/tap/blogsync

https://github.com/x-motemen/blogsync/releases から実行ファイルを直接取得できます。

ソースコードから最新版を使いたい場合は go install github.com/x-motemen/blogsync@latest してください。

Usage

Configuration

まず初めに設定ファイルを準備します。設定ファイルには以下の2種類があります。

  • ローカル設定: ./blogsync.yaml
  • グローバル設定: ~/.config/blogsync/config.yaml

両方存在する場合、設定の内容はマージされますが、ローカル設定の内容が優先されます。

設定ファイルの内容は以下のようなYAMLです。

motemen.hatenablog.com:
  username: motemen
  password: <API KEY>
default:
  local_root: /Users/motemen/Dropbox/Blog

各項目の意味は次のとおり:

  • キー(例: motemen.hatenablog.com ): ブログID (blogID)。はてなブログのダッシュボードからブログの設定画面などを開いたとき、URL に含まれる文字列です。技術的には AtomPub API における「ブログID」になります。独自ドメインを利用していない場合は配信ドメインと一致します。
    • "default" という名前のキーは特別で、すべてのブログの項目のデフォルト値として扱われます。
  • <blog>.username: そのブログに投稿するはてなユーザの ID。
  • <blog>.password: そのブログに投稿するための API キー。はてなユーザのパスワードではありません。ブログの詳細設定画面 の「APIキー」で確認できます。
  • <blog>.local_root: ブログのエントリを格納するパスのルート。
    • $local_root/$blogID/ 配下にエントリが格納されます。omit_domain 設定がされている場合はブログIDは含まれず、local_root直下にエントリーが格納されます
  • <blog>.omit_domain: ブログエントリを格納するパスにブログIDを含めません。
  • <blog>.owner: 編集対象のブログオーナーが自身とは別のユーザーの場合、ブログオーナーを個別に設定できます。

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

複数人で編集するブログなどで、編集者とブログのオーナーが別ユーザーの場合は下記のように設定できます。

example.hatenablog.com:
  username: sample
  password: <API KEY>
  owner: <OWNER>

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

設定が完了したら、以下のコマンドを実行すると当該のブログに投稿しているエントリがその URL ローカルに保存されます。固定ページ機能を利用している場合、それもまとめてダウンロードされます。

% blogsync pull <blogID>

この際保存されるファイルのパスは、エントリの URL ベースにしたものとなります。blogsync pull motemen.hatenablog.com した結果だとこんな感じになります(分かりやすいように少し省略しています):

/Users/motemen/Dropbox/Blog/motemen.hatenablog.com/
└── entry
    ├── 2014
    │   ├── 05
    │   │   ├── 12
    │   │   │   └── gulp,_TypeScript,_Browserify_で_Chrome_拡張を書く.md
    │   │   └── 14
    │   │       └── datetime-sh.md
    │   ├── 06
    │   │   ├── 01
    │   │   │   └── introducing-ghq.md
    │   │   ├── 03
    │   │   │   └── git-hub-sync-repo-info.md
…

以降は blogsync pull すると、ブログエントリとローカルのファイルをつき合わせ、新しいエントリのみダウンロードされるようになります。

ちなみに、blogIDは省略可能で、省略した場合 blogsync.yaml に設定されているブログの内容がpullされます。

ファイルのフォーマット

エントリのファイルはYAML Frontmatter形式のメタデータではじまり、そののち本文が続く、というフォーマットです:

---
Title:   まだmechanizeで消耗してるの? WebDriverで銀行をスクレイピング(ProtractorとWebdriverIOを例に)
Category:
- scraping
Date:    2014-10-01T08:30:00+09:00
URL:     http://motemen.hatenablog.com/entry/2014/10/01/scrape-by-protractor-webdriverio
EditURL: https://blog.hatena.ne.jp/motemen/motemen.hatenablog.com/atom/entry/8454420450066634133
---

今日はスクレイピングの話をします。…

今のところメタデータの内容は以下の6つ。

  • Title: エントリのタイトル。
  • Date: ブログに表示されるエントリの投稿日時。2006-01-02T15:04:05-07:00 といったフォーマットを期待しています。
  • URL: エントリの URL。これは自動的に与えられ、書き換えても効果はありません。
  • EditURL: エントリを一意に区別する URL。名前のとおり、AtomPub の編集用の URL です。
  • Category: エントリーのカテゴリの配列
  • Draft: この値が "yes" のとき、下書きとして扱われます。

エントリを更新する(blogsync push)

ひとたびエントリをダウンロードしたら、そのファイルを編集することで記事を更新できます。

% blogsync push <path/to/file>

例えばこんな感じですね:

% blogsync push ~/Dropbox/blog/motemen.hatenablog.com/entry/2014/12/22/blogsync.md
       GET ---> https://blog.hatena.ne.jp/motemen/motemen.hatenablog.com/atom/entry/8454420450077731341
       200 <--- https://blog.hatena.ne.jp/motemen/motemen.hatenablog.com/atom/entry/8454420450077731341
       PUT ---> https://blog.hatena.ne.jp/motemen/motemen.hatenablog.com/atom/entry/8454420450077731341
       200 <--- https://blog.hatena.ne.jp/motemen/motemen.hatenablog.com/atom/entry/8454420450077731341
     store /Users/motemen/Dropbox/blog/motemen.hatenablog.com/entry/2014/12/22/blogsync.md

ファイルがリモートの記事よりも新しくない場合は、更新リクエストは行われません。

基本的にはダウンロードしてきたファイルを更新する用途のコマンドですが、新しくファイルを配置してpushすることも可能です。

エントリを投稿する(blogsync post)

まだはてなブログ側に存在しない記事を投稿する場合は、投稿用のコマンドで記事を投稿します。

% blogsync post <blog> < <path/to/file>

blogsync post は標準入力からエントリの内容を受けとって投稿し、投稿されたエントリに対応するファイルをダウンロードします。その後は新しく作成されたファイルを編集し、push することでエントリの編集を続けられます。

このコマンドでは --title=<TITLE>--draft という引数によって記事タイトルや下書き状態の指定を行えるのでこんな風に雑に、ターミナルから書き始めることもできます…

% blogsync post --draft --title=blogsync motemen.hatenablog.com
さてかきはじめるか…
^D

特定のエントリを更新する (blogsync fetch)

エントリファイルを指定して、リモートの更新を取り込むことができます。

% blogsync fetch <path/to/file>

GitHub Actions

uses: x-motemen/blogsync@v0 とすればblogsyncをインストールできます。

Author

motemen, Songmu

blogsync's People

Contributors

autopp avatar codeout avatar github-actions[bot] avatar halkt avatar itchyny avatar kiririmode avatar lufia avatar mahito avatar motemen avatar nabeo avatar ongaeshi avatar songmu avatar suzuki-shunsuke avatar t-mrt avatar tarao avatar theoremoon avatar w-haibara avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

blogsync's Issues

$ go get failed because of "cli" package dependency

When I tried to install this product with command $ go get github.com/motemen/blogsync, or $ cd ${GOPATH}/src/github.com/motemen/blogsync && go build -o blogsync after cloning this git repository, the following error has occurred, regardless of where the installation was tried, such as on my local machine(WindowsPowerShell) or on remote host(CircleCI-GoContainer).

C:\Users\***\go\src\github.com\motemen\blogsync\main.go:17:15: cannot use []cli.Command literal (type []cli.Command) as type []*cli.Command in assignment
C:\Users\***\go\src\github.com\motemen\blogsync\main.go:157:15: cannot use cli.BoolFlag literal (type cli.BoolFlag) as type cli.Flag in array or slice literal:
        cli.BoolFlag does not implement cli.Flag (Apply method has pointer receiver)
C:\Users\***\go\src\github.com\motemen\blogsync\main.go:158:17: cannot use cli.StringFlag literal (type cli.StringFlag) as type cli.Flag in array or slice literal:
        cli.StringFlag does not implement cli.Flag (Apply method has pointer receiver)
C:\Users\***\go\src\github.com\motemen\blogsync\main.go:159:17: cannot use cli.StringFlag literal (type cli.StringFlag) as type cli.Flag in array or slice literal:
        cli.StringFlag does not implement cli.Flag (Apply method has pointer receiver)
$ #!/bin/bash -eo pipefail
cd ${GOPATH}/src/github.com/motemen/blogsync && go build -o blogsync
# github.com/motemen/blogsync
./main.go:17:15: cannot use []cli.Command literal (type []cli.Command) as type []*cli.Command in assignment
./main.go:157:15: cannot use cli.BoolFlag literal (type cli.BoolFlag) as type cli.Flag in array or slice literal:
    cli.BoolFlag does not implement cli.Flag (Apply method has pointer receiver)
./main.go:158:17: cannot use cli.StringFlag literal (type cli.StringFlag) as type cli.Flag in array or slice literal:
    cli.StringFlag does not implement cli.Flag (Apply method has pointer receiver)
./main.go:159:17: cannot use cli.StringFlag literal (type cli.StringFlag) as type cli.Flag in array or slice literal:
    cli.StringFlag does not implement cli.Flag (Apply method has pointer receiver)

Exited with code exit status 2

I guess that the dependency between main.go and urfave/cli, which is mentioned as one of imported packages in main.go, leads this error. For your information, urfave/cli branched off in autumn 2019, and now there are two versions of that component, then import method written below may result in installation of urfave/cli/v1.

import (
	"github.com/urfave/cli"
)

cf. https://github.com/urfave/cli
cf. swaggo/swag#556

So I want to let you know the phenomenon, and I hope you would fix this issue.

Best regards.

記事削除機能

ちょっと怖いけど、e2eテストとかで後片付けする目的とかでも欲しくなる。

Error when an entry is posted from stdin

When I try to post an entry from stdin, an error occured like this.

panic: runtime error: invalid memory address or nil pointer dereference
[signal 0xb code=0x1 addr=0x0 pc=0x4149]

goroutine 1 [running]:
main.(*Entry).atom(0xc20803d2f0, 0x2a)
        /Users/naoty/src/github.com/motemen/blogsync/entry.go:103 +0xe9
main.(*Broker).PostEntry(0xc20802b0b0, 0xc20803d2f0, 0x0, 0x0)
        /Users/naoty/src/github.com/motemen/blogsync/broker.go:138 +0x1a9
main.func·003(0xc2080781c0)
        /Users/naoty/src/github.com/motemen/blogsync/main.go:142 +0x567
github.com/codegangsta/cli.Command.Run(0x3e6b30, 0x4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x429590, 0x1a, 0x0, ...)
        /Users/naoty/src/github.com/codegangsta/cli/command.go:118 +0x104b
github.com/codegangsta/cli.(*App).Run(0xc2080a8000, 0xc20800a000, 0x4, 0x4, 0x0, 0x0)
        /Users/naoty/src/github.com/codegangsta/cli/app.go:154 +0xd04
main.main()
        /Users/naoty/src/github.com/motemen/blogsync/main.go:20 +0x149
  • OS: OS X mavericks
  • Go: 1.4.2

エントリー追加をやりやすくする

#91 でリモートに存在しない記事のMarkdownもpushできるようになったが、これを利用して新規エントリーを追加しやすくする仕組みを作る。

zenn new:articlehugo new content のようなインターフェースを提供できると良さそう。

予約投稿

いまはAPIでは不可能。バッチ処理で明示的にblogsync postするとかしないという手とかはあるが…

標準入力を経由せずに投稿する機能が欲しい

Windows だと標準入力を渡そうとしたときにエラーがでてしまいます。今はブラウザで空の記事を作成してから blogsync pull して回避しています。

Error CreateFile /dev/stdin: The system cannot find the path specified.

標準入力を経由せずに投稿することはできるでしょうか?空の記事を作成したり内容を引数渡せたりするとありがたいです。

blogsync post --draft --title=blogsync motemen.hatenablog.com  --content=さて何を書こうかな

customPath周りのupdate

  • AtomPubのレスポンスにはcustom urlは入っていないのでローカルにも持たせなくて良い
  • custom pathが変更された場合(ファイル名変更など)、ちゃんと追随する

`blogsync pull` で `[400 Bad Request]: "<p class=\"error-box\"></p>\n"` エラーが発生します

v0.14.1 において、blogsync pull を行ったところ、[400 Bad Request]: "<p class=\"error-box\"></p>\n" というエラーが発生し、記事の pull ができません。
v0.13.5 では正常に pull できます。

blogsync.yaml および BLOGSYNC_PASSWORD は設定済みです。

v0.14.1

blogsync --version
blogsync version 0.14.1 (HEAD)blogsync pull korosuke613.hatenablog.com
       GET ---> https://blog.hatena.ne.jp/korosuke613/korosuke613.hatenablog.com/atom/entry
       200 <--- https://blog.hatena.ne.jp/korosuke613/korosuke613.hatenablog.com/atom/entry
       GET ---> https://blog.hatena.ne.jp/korosuke613/korosuke613.hatenablog.com/atom/entry?page=1601117813
       200 <--- https://blog.hatena.ne.jp/korosuke613/korosuke613.hatenablog.com/atom/entry?page=1601117813
       GET ---> https://blog.hatena.ne.jp/korosuke613/korosuke613.hatenablog.com/atom/entry?page=1601044995
       200 <--- https://blog.hatena.ne.jp/korosuke613/korosuke613.hatenablog.com/atom/entry?page=1601044995
       GET ---> https://blog.hatena.ne.jp/korosuke613/korosuke613.hatenablog.com/atom/entry?page=1581430718
       200 <--- https://blog.hatena.ne.jp/korosuke613/korosuke613.hatenablog.com/atom/entry?page=1581430718
       GET ---> https://blog.hatena.ne.jp/korosuke613/korosuke613.hatenablog.com/atom/entry?page=1575293288
       200 <--- https://blog.hatena.ne.jp/korosuke613/korosuke613.hatenablog.com/atom/entry?page=1575293288
       GET ---> https://blog.hatena.ne.jp/korosuke613/korosuke613.hatenablog.com/atom/entry?page=1550944815
       200 <--- https://blog.hatena.ne.jp/korosuke613/korosuke613.hatenablog.com/atom/entry?page=1550944815
       GET ---> https://blog.hatena.ne.jp/korosuke613/korosuke613.hatenablog.com/atom/entry?page=1548517065
       200 <--- https://blog.hatena.ne.jp/korosuke613/korosuke613.hatenablog.com/atom/entry?page=1548517065
       GET ---> https://blog.hatena.ne.jp/korosuke613/korosuke613.hatenablog.com/atom/page
       400 <--- https://blog.hatena.ne.jp/korosuke613/korosuke613.hatenablog.com/atom/page
     error got [400 Bad Request]: "<p class=\"error-box\"></p>\n"echo $?
1

go install github.com/x-motemen/[email protected] を使って macOS 13.5.2 にインストールしました。

v0.13.5

blogsync --version
blogsync version 0.13.5 (5d82a9f)blogsync pull korosuke613.hatenablog.com
       GET ---> https://blog.hatena.ne.jp/korosuke613/korosuke613.hatenablog.com/atom/entry
       200 <--- https://blog.hatena.ne.jp/korosuke613/korosuke613.hatenablog.com/atom/entry
       GET ---> https://blog.hatena.ne.jp/korosuke613/korosuke613.hatenablog.com/atom/entry?page=1601117813
       200 <--- https://blog.hatena.ne.jp/korosuke613/korosuke613.hatenablog.com/atom/entry?page=1601117813
       GET ---> https://blog.hatena.ne.jp/korosuke613/korosuke613.hatenablog.com/atom/entry?page=1601044995
       200 <--- https://blog.hatena.ne.jp/korosuke613/korosuke613.hatenablog.com/atom/entry?page=1601044995
       GET ---> https://blog.hatena.ne.jp/korosuke613/korosuke613.hatenablog.com/atom/entry?page=1581430718
       200 <--- https://blog.hatena.ne.jp/korosuke613/korosuke613.hatenablog.com/atom/entry?page=1581430718
       GET ---> https://blog.hatena.ne.jp/korosuke613/korosuke613.hatenablog.com/atom/entry?page=1575293288
       200 <--- https://blog.hatena.ne.jp/korosuke613/korosuke613.hatenablog.com/atom/entry?page=1575293288
       GET ---> https://blog.hatena.ne.jp/korosuke613/korosuke613.hatenablog.com/atom/entry?page=1550944815
       200 <--- https://blog.hatena.ne.jp/korosuke613/korosuke613.hatenablog.com/atom/entry?page=1550944815
       GET ---> https://blog.hatena.ne.jp/korosuke613/korosuke613.hatenablog.com/atom/entry?page=1548517065
       200 <--- https://blog.hatena.ne.jp/korosuke613/korosuke613.hatenablog.com/atom/entry?page=1548517065
     fresh remote=2023-01-05 04:10:57 +0900 JST > local=0001-01-01 00:00:00 +0000 UTC
     store entries/korosuke613.hatenablog.com/entry/2023/01/03/hofu-2023.md
     fresh remote=2022-08-20 21:32:51 +0900 JST > local=0001-01-01 00:00:00 +0000 UTC
     store entries/korosuke613.hatenablog.com/entry/activity-2021.md
     fresh remote=2021-12-01 21:05:47 +0900 JST > local=0001-01-01 00:00:00 +0000 UTC
<省略>echo $?
0

Homebrew を使って macOS 13.5.2 にインストールしました。

Note

元々 https://github.com/hatena/Hatena-Blog-Workflows-Boilerplate を使って blogsync pull をしたところこの問題に遭遇しました。

image

https://github.com/korosuke613/hatena-articles/actions/runs/6453237700/job/17516453758#step:4:23

blogsync pullの引数を省略可能にする

blogsync pull <BlogID>

のように現状BlogIDが引数で必須になっているが、同じディレクトリに blogsync.yaml がある場合は引数を省略可能にしたい。blogsync.yamlに複数の設定がある場合は、一律pullするか、対応しないか要検討だが、一律pullで良いのでは?

下書きでURLが未確定の場合の保存先をどうするか

現在 link[rel=alternate] から保存先を決めているが、このURLは下書き時は仮のもので、特にカスタムパスを定めていない場合、下書き保存時に毎回変更される(日付ベースになっているため)

https://github.com/hatena/hatenablog-workflows

はてな社のワークフローの場合、 draft_entries/ に $blogID.md で保存している。

カスタムパスが指定されているか否かを完全に判別するのは少し難しく、状況証拠的に区別するしか無い。

Windows(Powershell)で実行すると、エントリーファイル内のヘッダーが読みこまれない

概要

Powershell上で公開済みエントリーを管理するファイルを用いてblogsync pushを実行したところ、以下エラーになってpushできなかった。

> blogsync push path/to/file.md
     error "(対象のファイルパス)" is not a blog entry

動作環境

  • OS 名 Microsoft Windows 11 Pro
  • バージョン 10.0.22621 ビルド 22621
  • Powershellバージョン
    Name                           Value
    ----                           -----
    PSVersion                      7.4.1
    PSEdition                      Core
    GitCommitId                    7.4.1
    OS                             Microsoft Windows 10.0.22621
    Platform                       Win32NT
    PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0…}
    PSRemotingProtocolVersion      2.3
    SerializationVersion           1.1.0.1
    WSManStackVersion              3.0
    
  • blogsync バージョン
    > blogsync -v
    blogsync.exe version 0.20.1 (9760a4c)
    

確認したこと

log.Printf("%+v",entry) のように何が足りてないか確認していったところ、entryHeaderの中身が空になっていました。
以下2行にて指定している、区切り文字を ---\n から ---\r\n に変更したところ、entryHeaderの取得に成功し、pushに成功しました。

が、Windows向け動作をどのように仕込むとよいかわからずぱっとPRを出せなそうだったとの、当方の使い方がよろしくないのかわからなかったので、取り急ぎissueを作成しました。

サブディレクトリ運用時のファイル保存先

ブログメディアのサブディレクトリ運用をしている時、blogsyncは現状、 url.Path に対応する部分にファイルを保存しているため (

return filepath.Join(b.localRoot(), e.URL.Path+entryExt)
) 、例えば、 https://blog.example.com/subdir/entry/hoge というエントリーは $local_root/subdir/entry/hoge に保存される。

これはあまり嬉しくないのではないか。 $local_root/entry/hoge に保存されて欲しい。その様に変更した場合に $local_root/subdir に保存したい場合は、 local_rootの設定に subdirを含めれば良い。

ただこれを変えてしまうと破壊的変更になるし、多分MackerelのDocumentがこの挙動に依存したワークフローを組んでいる気がする。

https://github.com/mackerelio/documents

Preview オプションの追加

2023年10月16日 app:control/app:preview 要素 が増えたようです。

app:control/app:preview要素
ブログエントリが下書きのとき下書きプレビューの共有URLを発行するか指定できます。"yes"を指定すると共有URLが発行され、レスポンスのrel=previewであるatom:link要素のhref属性が共有URLとなります。指定を行わなかった場合、下書きプレビュー用の共有URLは発行されません。また、下書きではないエントリに対して"yes"を指定しても無効となります。
https://developer.hatena.ne.jp/ja/documents/blog/apis/atom

`make devel-deps` is failed due to path of golint

make devel-deps failed as the followings.

$ make devel-deps
go get  github.com/golang/dep/cmd/dep
dep ensure
go get  github.com/golang/lint/golint \
	  github.com/haya14busa/goverage          \
	  github.com/mattn/goveralls              \
	  github.com/motemen/gobump               \
	  github.com/Songmu/goxz/cmd/goxz         \
	  github.com/Songmu/ghch                  \
	  github.com/tcnksm/ghr
package github.com/golang/lint/golint: code in directory /Users/autopp/go/src/github.com/golang/lint/golint expects import "golang.org/x/lint/golint"
make: *** [devel-deps] Error 1

It seems to be caused by the path of golint being changed.
golang/lint#415

test enhancement

実際のXMLとかをtestdateとして持ってテストするようにしたい

blogsync push stores the content to different filename than the original name

I had a draft entry posted already to hatenablog CMS. It was stored to entry/2019/08/21/020240.md, and it had URL entry header.

$ sed -n '/---/,/---/p' entry/2019/08/21/020240.md
---
Title: title-title-title
Date: 2019-08-21T02:02:40+09:00
URL: https://example.org/entry/2019/08/21/020240
EditURL: https://blog.hatena.ne.jp/user/example.hateblo.jp/atom/entry/26006613401156491
Draft: true
---

Today, I updated the draft entry then pushed it. In that case entry/2019/08/21/020240.md is not modified. Instead blogsync push created a new file named entry/2020/03/29/162048.md.

$ blogsync push entry/2019/08/21/020240.md 
       GET ---> https://blog.hatena.ne.jp/user/example.hateblo.jp/atom/entry/26006613401156491
       200 <--- https://blog.hatena.ne.jp/user/example.hateblo.jp/atom/entry/26006613401156491
       PUT ---> https://blog.hatena.ne.jp/user/example.hateblo.jp/atom/entry/26006613401156491
       200 <--- https://blog.hatena.ne.jp/user/example.hateblo.jp/atom/entry/26006613401156491
     store entry/2020/03/29/162048.md

Is this by design?

エラーメッセージをわかりやすくする

現状pushやpostコマンド等で想定していない入力があった場合に対するエラーメッセージが不足している.
例えば以下のコマンドを入力した際に,何も表示されない.そのためどれが起因してエラーが発生しているかがわからない.

 $ ~: blogsync post

READMEやソースコードを見ればわかる部分多いですが,余裕があれば追加していただけると助かります.

ファイルの最終更新をgit logから取れたら取る

今、エントリーのファイルの更新時間をリモートと比較する時にファイルのmtimeを使っている。しかし今どきmtimeだけというのも頼りない。例えば、CIとかでgit cloneしてきた直後などはmtimeが全部現在時間になってしまい、ローカルが全部リモートより新しいと判定されてしまうなどがある。 (gitにはsvnのuse-commit-times的な機能はオフィシャルで存在しないし / 以前 git-set-mtime をメンテしていた)

git履歴からファイルの更新日時が取れる場合はそれを使うようにしたい。VCSでgitを特別扱いするのはどうなのか、blogsyncがgitに依存するのはどうなのか、という議論はあるが、実際問題git管理している人も多かろうと思うので悪くないのではないか。

以下のようにすれば、gitが入っていな環境や、そのファイルがgit管理されていないケースでもそれを壊さないはず。

  • gitコマンドが入っているか確認する
  • 当該ファイルがgit管理されているか確認する
  • そのファイルがgit上でクリーンか(modifiedになっていないか)確認する
  • 上記の条件を満たした場合、そのファイルのgit上の最終更新時間を、そのファイルの最終更新時間として扱う

FrontomaterのURLフィールド再考

  • 特にDraftの場合まだ公開予定地であって確定していない
    • 特にカスタムパスを設定していない場合
    • 実際公開直線まで変わりうる
      • はてなブログ内部的には公開時に確定する
    • 下書き時はなくても良さそう
  • 公開されたものであってもMarkdown格納位置からURLはほぼ自明なので、それも含めて埋めなくてもいいという説もある
    • そこの値を編集したらURLが変更できるという勘違いも生まれやすい

ref. #99

command to display managed blogs

This issue is a feature request.
I want a command which read config files and display maneged blogs to stdout.

E.g.

$ blogsync list
autopp.hatenablog.com
autopp-tech.hatenablog.com

I think that if this command is available it will be useful for command line completion.

新規ドラフト記事を投稿時、ディレクトリ構成によって記事の格納先が変わる

blogsync pull で作成されるディレクトリ構成(entry/${year}/${month}/${day}/)とそうでない場合で記事の格納先が異なり、意図せず EditURL などが反映されないことがある。

  • entry/${year}/${month}/${day}/file の場合: entry/_draft/ に新規ファイルとして PreviewURL などを格納(push したファイルに追記なし)
% blogsync push entry/2023/11/17/test_entry.md
      POST ---> https://blog.hatena.ne.jp/mazinlabs/mahito.hatenablog.com/atom/entry
       201 <--- https://blog.hatena.ne.jp/mazinlabs/mahito.hatenablog.com/atom/entry
     store /Users/mahito/repos/github/mahito.hatenablog.com/entry/_draft/6801883189059489955.md
% blogsync fetch entry/2023/11/17/test_entry.md
     error failed to get blogID form EditURL:
  • 上記以外の場合: push したファイルに追記
% blogsync push entry/2023/11/test_entry.md
      POST ---> https://blog.hatena.ne.jp/mazinlabs/mahito.hatenablog.com/atom/entry
       201 <--- https://blog.hatena.ne.jp/mazinlabs/mahito.hatenablog.com/atom/entry
     store /Users/mahito/repos/github/mahito.hatenablog.com/entry/2023/11/test_entry.md
% blogsync fetch entry/2023/11/test_entry.md
       GET ---> https://blog.hatena.ne.jp/mazinlabs/mahito.hatenablog.com/atom/entry/6801883189059489023
       200 <--- https://blog.hatena.ne.jp/mazinlabs/mahito.hatenablog.com/atom/entry/6801883189059489023

Categories are dropped on updating a blog post

When I update a blog post by pulling and pushing the post as the following, the categories of the post are dropped after pushing it.

$ blogsync pull myblog
$ vi entry/some/blog/post
$ blogsync push entry/some/blog/post

make test failed due to double quotes in `Date`

make test failed as the followings. Apparently, the cause of errors is double quotes in Date.

$ go version
go version go1.10.1 darwin/amd64

$ make test
go get  -d -t -v ./...
go test ./...
--- FAIL: TestFullContent (0.00s)
        entry_test.go:56:
                        Error Trace:    entry_test.go:56
                        Error:          Not equal:
                                        expected: "---\nTitle: 所内#3\nDate: \"2012-12-19T00:00:00+09:00\"\nURL: http://hatenablog.example.com/1\nEditURL: http://hatenablog.example.com/1/edit\n---\n\ntest\ntest2\n"
                                        actual  : "---\nTitle: 所内#3\nDate: 2012-12-19T00:00:00+09:00\nURL: http://hatenablog.example.com/1\nEditURL: http://hatenablog.example.com/1/edit\n---\n\ntest\ntest2\n"
                        Test:           TestFullContent
--- FAIL: TestDraftFullContent (0.00s)
        entry_test.go:99:
                        Error Trace:    entry_test.go:99
                        Error:          Not equal:
                                        expected: "---\nTitle: 所内#4\nDate: \"2012-12-20T00:00:00+09:00\"\nURL: http://hatenablog.example.com/2\nEditURL: http://hatenablog.example.com/2/edit\nDraft: true\n---\n\n下書き\n"
                                        actual  : "---\nTitle: 所内#4\nDate: 2012-12-20T00:00:00+09:00\nURL: http://hatenablog.example.com/2\nEditURL: http://hatenablog.example.com/2/edit\nDraft: true\n---\n\n下書き\n"
                        Test:           TestDraftFullContent
--- FAIL: TestUnmarshalYAML (0.00s)
        entry_test.go:135:
                        Error Trace:    entry_test.go:135
                        Error:          Not equal:
                                        expected: "Title: 所内\nCategory:\n- foo\n- bar\nDate: 2012-12-20T00:00:00+09:00\nURL: http://hatenablog.example.com/2\nEditURL: http://hatenablog.example.com/2/edit\n"
                                        actual  : "Title: 所内\nCategory:\n- foo\n- bar\nDate: \"2012-12-20T00:00:00+09:00\"\nURL: http://hatenablog.example.com/2\nEditURL: http://hatenablog.example.com/2/edit\n"
                        Test:           TestUnmarshalYAML
FAIL
FAIL    github.com/motemen/blogsync     0.051s
ok      github.com/motemen/blogsync/atom        (cached)
make: *** [test] Error 1

I investigated to fix that, but I'm not confident which (w/ or w/o double quotes) is right.
At least, I think the difference is stems from results of Marshaling time.Date and entryTime...

	date := time.Date(2012, 12, 19, 0, 0, 0, 0, jst)

	md, _ := yaml.Marshal(date)
	me, _ := yaml.Marshal(&entryTime{&d})

	fmt.Println(string(md)) # 2012-12-19T00:00:00+09:00
	fmt.Println(string(me)) # "2012-12-19T00:00:00+09:00"

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.