├── t
├── hexo
│ ├── test.md
│ ├── 2016-07-30-LLD-in-zabbix.markdown
│ └── test-html.html
└── hugo
│ ├── test.md
│ ├── test-html.md
│ ├── LLD-in-zabbix.markdown
│ └── test-html.html
├── LICENSE
├── README.md
└── hexo2hugo.py
/t/hexo/test.md:
--------------------------------------------------------------------------------
1 | title: ttttt
2 | date: 2016-07-30 14:09:58
3 | permalink: Just-a-test
4 | tags: zabbix
5 | ---
6 | test
7 |
--------------------------------------------------------------------------------
/t/hugo/test.md:
--------------------------------------------------------------------------------
1 | +++
2 | title = "ttttt"
3 | date = "2016-07-30T14:09:58+08:00"
4 | tags = ["zabbix"]
5 | description = ""
6 | slug = "Just-a-test"
7 | +++
8 |
9 | test
10 |
--------------------------------------------------------------------------------
/t/hugo/test-html.md:
--------------------------------------------------------------------------------
1 | +++
2 | title = "test html"
3 | date = "2016-07-30T14:09:58+08:00"
4 | tags = ["zabbix"]
5 | description = ""
6 | slug = "Just-a-test"
7 | +++
8 |
9 | test
10 |
11 | fffss
12 | fffff
13 | fssss
14 | fsdfsdfsdf
15 |
16 | sdfsdf
17 |
--------------------------------------------------------------------------------
/t/hexo/2016-07-30-LLD-in-zabbix.markdown:
--------------------------------------------------------------------------------
1 | title: Test file
2 | date: 2016-07-30 14:09:58
3 | permalink: Just a test
4 | tags:
5 | - zabbix
6 | - monitor
7 | categories:
8 | - Test
9 | - te
10 | ---
11 | 如果需要监控的内容比较多的时候,手动管理报警信息就已经不使用了,加一批机器就需要忙活一阵子。也不能体现我们充满智慧的大脑的作用。
12 |
13 | test
14 |
--------------------------------------------------------------------------------
/t/hexo/test-html.html:
--------------------------------------------------------------------------------
1 | title: test html
2 | date: 2016-07-30 14:09:58
3 | permalink: Just-a-test
4 | tags: zabbix
5 | ---
6 | test
7 |
8 | fffss
9 | fffff
10 | fssss
11 | fsdfsdfsdf
12 |
13 | sdfsdf
14 |
15 |
16 | fffffsdf
17 | sdfsdf
18 | sdfsdfsdf sdfsdf
19 |
20 |
--------------------------------------------------------------------------------
/t/hugo/LLD-in-zabbix.markdown:
--------------------------------------------------------------------------------
1 | +++
2 | title = "Test file"
3 | date = "2016-07-30T14:09:58+08:00"
4 | tags = ["zabbix", "monitor"]
5 | categories = ["Test", "te"]
6 | description = ""
7 | slug = "Just a test"
8 | +++
9 |
10 | 如果需要监控的内容比较多的时候,手动管理报警信息就已经不使用了,加一批机器就需要忙活一阵子。也不能体现我们充满智慧的大脑的作用。
11 |
12 | test
13 |
--------------------------------------------------------------------------------
/t/hugo/test-html.html:
--------------------------------------------------------------------------------
1 | +++
2 | title = "test html"
3 | date = "2016-07-30T14:09:58+08:00"
4 | tags = ["zabbix"]
5 | description = ""
6 | slug = "Just-a-test"
7 | +++
8 |
9 | test
10 |
11 | fffss
12 | fffff
13 | fssss
14 | fsdfsdfsdf
15 |
16 | sdfsdf
17 |
18 |
19 | fffffsdf
20 | sdfsdf
21 | sdfsdfsdf sdfsdf
22 |
23 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017 wd
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Intro
2 |
3 | Tools to help you migrate files from hexo to hugo.
4 |
5 | # Usage
6 |
7 | ```
8 | usage: hexo2hugo.py [-h] [--src SRC] [--dest DEST] [--remove-date-from-name]
9 | [--verbose]
10 |
11 | optional arguments:
12 | -h, --help show this help message and exit
13 | --src SRC Hexo posts directory
14 | --dest DEST Destination directory
15 | --remove-date-from-name
16 | Remove date from file name
17 | --verbose Output level
18 | ```
19 |
20 | Example:
21 |
22 | ```
23 | $ ./hexo2hugo.py --src=./t/hexo/ --dest=./t/hugo/ --remove-date-from-name --verbose
24 | Hexo2hugo (Hexo): [INFO] Total 3 files found
25 | Hexo2hugo (Hexo): [INFO] Process 2016-07-30-LLD-in-zabbix.markdown now, meta: {'title': 'Test file', 'date': datetime.datetime(2016, 7, 30, 14, 9, 58), 'permalink': 'Just a test', 'tags': ['zabbix', 'monitor'], 'categories': ['Test', 'te']}, body length: 71
26 | Hexo2hugo (Hexo): [INFO] Write to LLD-in-zabbix.markdown, meta: title = "Test file"
27 | date = "2016-07-30T14:09:58+08:00"
28 | tags = ["zabbix", "monitor"]
29 | categories = ["Test", "te"]
30 | description = ""
31 | slug = "Just a test"
32 |
33 | Hexo2hugo (Hexo): [INFO] Process test-html.html now, meta: {'title': 'test html', 'date': datetime.datetime(2016, 7, 30, 14, 9, 58), 'permalink': 'Just-a-test', 'tags': 'zabbix'}, body length: 147
34 | Hexo2hugo (Hexo): [INFO] Write to test-html.html, meta: title = "test html"
35 | date = "2016-07-30T14:09:58+08:00"
36 | tags = ["zabbix"]
37 | description = ""
38 | slug = "Just-a-test"
39 |
40 | Hexo2hugo (Hexo): [INFO] Process test.md now, meta: {'title': 'ttttt', 'date': datetime.datetime(2016, 7, 30, 14, 9, 58), 'permalink': 'Just-a-test', 'tags': 'zabbix'}, body length: 5
41 | Hexo2hugo (Hexo): [INFO] Write to test.md, meta: title = "ttttt"
42 | date = "2016-07-30T14:09:58+08:00"
43 | tags = ["zabbix"]
44 | description = ""
45 | slug = "Just-a-test"
46 | ```
47 |
48 | It is used by me and may not fit your situation, feel free to fork and modify :)
49 |
--------------------------------------------------------------------------------
/hexo2hugo.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 |
4 | import argparse
5 | import os
6 | import logging
7 | import yaml
8 | import pytoml as toml
9 | import datetime
10 | import re
11 |
12 | default_logging_level = logging.WARNING
13 | default_timezome_offset = +datetime.timedelta(hours=8)
14 |
15 |
16 | class Logger(object):
17 | def __init__(self, name):
18 | logformat = 'Hexo2hugo (%(name)s): [%(levelname)s] %(message)s'
19 |
20 | self.logger = logging.getLogger(name or __name__)
21 | self.logger.setLevel(default_logging_level)
22 | myhandler = logging.StreamHandler()
23 | myhandler.setFormatter(logging.Formatter(logformat))
24 | self.logger.addHandler(myhandler)
25 |
26 |
27 | class Hexo2Hugo(object):
28 | def __init__(self, src, dest, remove_date):
29 | self.root_path = os.path.expanduser(src)
30 | self.dest_path = os.path.expanduser(dest)
31 | self.remove_date = remove_date
32 | self.logger = Logger("Hexo").logger
33 |
34 | self._find_all_files()
35 |
36 | def go(self):
37 | for post in self._process_files():
38 | name = post['name']
39 | meta = post['meta']
40 | body = post['body']
41 |
42 | if self.remove_date:
43 | name = self._remove_date(name)
44 |
45 | with open(os.path.join(self.dest_path, name), 'w+') as fp:
46 | self.logger.info("Write to {}, meta: {}".format(name, meta))
47 | fp.writelines("+++\n{}+++\n\n{}".format(meta, body))
48 |
49 | def _remove_date(self, name):
50 | new_name = re.sub('^\d+-\d+-\d+-(.*)', r'\1', name)
51 | if new_name:
52 | return new_name
53 | return name
54 |
55 | def _find_all_files(self):
56 | self.files = []
57 | for file in os.listdir(self.root_path):
58 | if os.path.isfile(os.path.join(self.root_path, file)):
59 | self.files.append(file)
60 | self.logger.info("Total {} files found".format(len(self.files)))
61 |
62 | def _extract_date_from_filename(self, filename):
63 | m = re.match('^(\d+-\d+-\d+)-.*$', filename)
64 | if m:
65 | return m.group(1)
66 |
67 | def _process_files(self):
68 | for hexo_file in self.files:
69 | date_from_filename = self._extract_date_from_filename(hexo_file)
70 | with open(os.path.join(self.root_path, hexo_file), 'r') as fp:
71 | meta_yaml = ''
72 | body = ''
73 | is_meta = True
74 | is_first_line = True
75 | is_in_pre = False
76 | for line in fp:
77 | if is_first_line:
78 | is_first_line = False
79 | if line == '---\n':
80 | continue
81 |
82 | if is_meta:
83 | if line == '---\n':
84 | is_meta = False
85 | else:
86 | meta_yaml += line
87 | else:
88 | if re.search(r'.html$', hexo_file):
89 | if re.search(r'^$', line):
96 | body += line[:-1] + "
\n"
97 | else:
98 | body += line
99 | else:
100 | body += line
101 | meta = yaml.load(meta_yaml)
102 |
103 | self.logger.info("Process {} now, meta: {}, body length: {}".format(hexo_file, meta, len(body)))
104 |
105 | if 'date' in meta:
106 | no_tz_date = meta['date']
107 | if type(no_tz_date) == str:
108 | no_tz_date = datetime.datetime.strptime(no_tz_date, '%Y-%m-%d %H:%M')
109 |
110 | meta['date'] = no_tz_date.replace(tzinfo=datetime.timezone(default_timezome_offset)).isoformat('T')
111 | else:
112 | meta['date'] = date_from_filename
113 |
114 | meta['description'] = ''
115 | if 'permalink' in meta:
116 | meta['slug'] = meta['permalink']
117 | del meta['permalink']
118 |
119 | if 'layout' in meta:
120 | del meta['layout']
121 |
122 | if 'tags' in meta and type(meta['tags']) == str:
123 | meta['tags'] = meta['tags'].split(',')
124 |
125 | meta_toml = toml.dumps(meta)
126 | yield({'name': hexo_file, 'meta': meta_toml, 'body': body})
127 |
128 |
129 | def main(args):
130 | hexo = Hexo2Hugo(args.src, args.dest, args.remove_date_from_name)
131 | hexo.go()
132 |
133 |
134 | if __name__ == '__main__':
135 | parser = argparse.ArgumentParser()
136 | parser.add_argument('--src', help='Hexo posts directory')
137 | parser.add_argument('--dest', help='Destination directory')
138 | parser.add_argument('--remove-date-from-name', help='Remove date from file name', action='store_true')
139 | parser.add_argument('--verbose', help='Output level', action='store_true')
140 |
141 | args = parser.parse_args()
142 |
143 | if args.verbose:
144 | default_logging_level = logging.DEBUG
145 |
146 | main(args)
147 |
--------------------------------------------------------------------------------