差分
このページの2つのバージョン間の差分を表示します。
次のリビジョン | 前のリビジョン | ||
python:moinmoin [2019/08/09 04:42] – 作成 ともやん | python:moinmoin [2021/07/05 02:40] (現在) – ともやん | ||
---|---|---|---|
行 1: | 行 1: | ||
====== MoinMoin ====== | ====== MoinMoin ====== | ||
- | {{:python: | + | {{python: |
\\ | \\ | ||
本家: [[https:// | 本家: [[https:// | ||
行 7: | 行 7: | ||
**MoinMoin** (モインモイン) は Python で書かれたウィキクローンの一つ。ユルゲン・ヘルマン、トーマス・ヴァルドマンらによって開発された。ライセンスはGPLである。Moinとは北部ドイツ等で話されるフリジア語の挨拶の言葉であり、直訳すると「よき一日を!」という意味である。\\ | **MoinMoin** (モインモイン) は Python で書かれたウィキクローンの一つ。ユルゲン・ヘルマン、トーマス・ヴァルドマンらによって開発された。ライセンスはGPLである。Moinとは北部ドイツ等で話されるフリジア語の挨拶の言葉であり、直訳すると「よき一日を!」という意味である。\\ | ||
[[https:// | [[https:// | ||
+ | |||
+ | ===== MoinMoin 2.0 ===== | ||
+ | **MoinMoin 2.0** は 2019/08/09 現在、開発中であり Python 3.5 以上に対応している。\\ | ||
+ | しかし、**quickinstall.py** は **virtualenv** を使用しており、**venv** には対応していない。\\ | ||
+ | 以下の手順では、**quickinstall.py** が **Python 3.7.4** で **venv** を利用するようにハックしてインストールを行う。\\ | ||
+ | |||
+ | ==== ダウンロード ==== | ||
+ | [[https:// | ||
+ | < | ||
+ | $ git clone --depth 1 https:// | ||
+ | </ | ||
+ | |||
+ | ==== quickinstall.py を venv を利用するようにハックする ==== | ||
+ | GitHub からダウンロードした **quickinstall.py** をリネームする。\\ | ||
+ | |||
+ | **Linux**\\ | ||
+ | <WRAP prewrap 100%> | ||
+ | < | ||
+ | $ cd moin | ||
+ | $ mv quickinstall.py quickinstall.py.org | ||
+ | </ | ||
+ | </ | ||
+ | |||
+ | **Windows**\\ | ||
+ | <WRAP prewrap 100%> | ||
+ | < | ||
+ | > cd moin | ||
+ | > ren quickinstall.py quickinstall.py.org | ||
+ | </ | ||
+ | </ | ||
+ | |||
+ | 以下の **quickinstall.py** を **moin** ディレクトリにダウンロードする。(**quickinstall.py** を差し替える)\\ | ||
+ | <WRAP prewrap 100%> | ||
+ | < | ||
+ | $ curl -O https:// | ||
+ | $ chmod 775 quickinstall.py | ||
+ | </ | ||
+ | </ | ||
+ | <WRAP prewrap 100% mincode_long> | ||
+ | <file python moin/ | ||
+ | # | ||
+ | # Copyright: 2013 MoinMoin: | ||
+ | # Copyright: 2013-2018 MoinMoin: | ||
+ | # License: GNU GPL v2 (or any later version), see LICENSE.txt for details. | ||
+ | """ | ||
+ | Create a virtual environment and install moin2 and all requirements in development mode. | ||
+ | |||
+ | Usage for installation: | ||
+ | |||
+ | < | ||
+ | |||
+ | Requires: Python 3.5+, virtualenv, pip | ||
+ | |||
+ | After initial installation, | ||
+ | moin2 developers and desktop wiki users. | ||
+ | |||
+ | - wraps a few commonly used moin commands, do "moin --help" | ||
+ | - adds default file names for selected moin commands (backup, restore, ...) | ||
+ | - creates log files for functions with large output, extracts success/ | ||
+ | - displays error messages if user tries to run commands out of sequence | ||
+ | - activates the virtual env in a subprocess (no need for user to do ". activate" | ||
+ | |||
+ | usage (to display a menu of commands): | ||
+ | |||
+ | - unix: ./m | ||
+ | - windows: | ||
+ | |||
+ | For the menu to work, it needs to know the name of a python executable and the location of a | ||
+ | virtual env. These needs are met by running " | ||
+ | repository. The first run of quickinstall.py creates these files or symlink in the repo root: | ||
+ | |||
+ | - unix: m, activate | ||
+ | - windows: m.bat, activate.bat, | ||
+ | |||
+ | Executing m.bat or ./m will run this script. The name of the python executable is within the | ||
+ | m.bat or ./m script. | ||
+ | Depending upon the command to be executed, some mix of the python executable | ||
+ | or activate will be used to construct a command string to pass to a subprocess call. | ||
+ | |||
+ | One possible command is "./m quickinstall" | ||
+ | update the virtualenv with newly released supporting software. If tests have been run, | ||
+ | then the two virtualenvs within the .tox directory are also updated. | ||
+ | """ | ||
+ | |||
+ | |||
+ | import argparse | ||
+ | import logging | ||
+ | import os | ||
+ | import subprocess | ||
+ | import sys | ||
+ | import platform | ||
+ | import glob | ||
+ | import shutil | ||
+ | import fnmatch | ||
+ | from collections import Counter | ||
+ | try: | ||
+ | import virtualenv | ||
+ | except ImportError: | ||
+ | sys.exit(""" | ||
+ | Error: import virtualenv failed, either virtualenv is not installed (see installation docs) | ||
+ | or the virtual environment must be deactivated before rerunning quickinstall.py | ||
+ | """ | ||
+ | |||
+ | if sys.hexversion < 0x3050000: | ||
+ | sys.exit(" | ||
+ | |||
+ | |||
+ | WIN_INFO = ' | ||
+ | NIX_INFO = 'the m bash script and the activate symlink are created by quickinstall.py' | ||
+ | |||
+ | # text files created by commands with high volume output | ||
+ | QUICKINSTALL = ' | ||
+ | TOX = ' | ||
+ | CODING_STD = ' | ||
+ | DOCS = ' | ||
+ | NEWWIKI = ' | ||
+ | DELWIKI = ' | ||
+ | BACKUPWIKI = ' | ||
+ | DUMPHTML = ' | ||
+ | EXTRAS = ' | ||
+ | DIST = ' | ||
+ | # default files used for backup and restore | ||
+ | BACKUP_FILENAME = os.path.normpath(' | ||
+ | JUST_IN_CASE_BACKUP = os.path.normpath(' | ||
+ | |||
+ | |||
+ | if os.name == ' | ||
+ | M = ' | ||
+ | ACTIVATE = ' | ||
+ | SEP = ' & ' | ||
+ | WINDOWS_OS = True | ||
+ | else: | ||
+ | M = ' | ||
+ | # in terminal " | ||
+ | ACTIVATE = '. ./activate; ' | ||
+ | SEP = ';' | ||
+ | WINDOWS_OS = False | ||
+ | |||
+ | |||
+ | # commands that create log files | ||
+ | CMD_LOGS = { | ||
+ | ' | ||
+ | ' | ||
+ | # ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | } | ||
+ | |||
+ | |||
+ | help = """ | ||
+ | |||
+ | usage: "{0} < | ||
+ | |||
+ | quickinstall | ||
+ | extras | ||
+ | docs create moin html documentation (requires extras) | ||
+ | interwiki | ||
+ | log < | ||
+ | |||
+ | new-wiki | ||
+ | sample | ||
+ | restore * | ||
+ | import19 < | ||
+ | |||
+ | run * run built-in wiki server *options (--port 8081) | ||
+ | backup * roll 3 prior backups and create new backup *option, specify file | ||
+ | dump-html * | ||
+ | index | ||
+ | |||
+ | css run Stylus and lessc to update theme CSS files | ||
+ | tests * run tests, log output (-v -k my_test) | ||
+ | coding-std | ||
+ | |||
+ | del-all | ||
+ | del-orig | ||
+ | del-pyc | ||
+ | del-rej | ||
+ | del-wiki | ||
+ | """ | ||
+ | |||
+ | |||
+ | def search_for_phrase(filename): | ||
+ | """ | ||
+ | files = { | ||
+ | # filename: (list of phrases) | ||
+ | # Note: phrases must be lower-case | ||
+ | QUICKINSTALL: | ||
+ | NEWWIKI: (' | ||
+ | BACKUPWIKI: (' | ||
+ | DUMPHTML: (' | ||
+ | # use of 'error ' below is to avoid matching .../ | ||
+ | EXTRAS: (' | ||
+ | # ': e' matches lines similar to: src/ | ||
+ | TOX: (' | ||
+ | CODING_STD: (' | ||
+ | DIST: (' | ||
+ | DOCS: (' | ||
+ | } | ||
+ | # for these file names, display a count of occurrances rather than each found line | ||
+ | print_counts = (CODING_STD, | ||
+ | |||
+ | with open(filename, | ||
+ | lines = f.readlines() | ||
+ | name = os.path.split(filename)[1] | ||
+ | phrases = files[name] | ||
+ | counts = Counter() | ||
+ | for idx, line in enumerate(lines): | ||
+ | for phrase in phrases: | ||
+ | if phrase in line.lower(): | ||
+ | if filename in print_counts: | ||
+ | counts[phrase] += 1 | ||
+ | else: | ||
+ | print(idx + 1, line.rstrip()) | ||
+ | break | ||
+ | for key in counts: | ||
+ | print(' | ||
+ | |||
+ | |||
+ | def wiki_exists(): | ||
+ | """ | ||
+ | return bool(glob.glob(' | ||
+ | |||
+ | |||
+ | def make_wiki(command, | ||
+ | """ | ||
+ | if wiki_exists() and mode == ' | ||
+ | print(' | ||
+ | else: | ||
+ | print(' | ||
+ | with open(NEWWIKI, | ||
+ | result = subprocess.call(command, | ||
+ | if result == 0: | ||
+ | print(msg) | ||
+ | return True | ||
+ | else: | ||
+ | print(' | ||
+ | search_for_phrase(NEWWIKI) | ||
+ | print(' | ||
+ | return False | ||
+ | |||
+ | |||
+ | def put_items(dir=' | ||
+ | """ | ||
+ | metas = [] | ||
+ | datas = [] | ||
+ | files = [] | ||
+ | for (dirpath, dirnames, filenames) in os.walk(dir): | ||
+ | files.extend(filenames) | ||
+ | break | ||
+ | for file in files: | ||
+ | if file.endswith(' | ||
+ | metas.append(file) | ||
+ | if file.endswith(' | ||
+ | datas.append(file) | ||
+ | if not len(datas) == len(metas): | ||
+ | print(' | ||
+ | return False | ||
+ | commands = [] | ||
+ | command = 'moin item-put --meta {0} --data {1}' | ||
+ | for meta in metas: | ||
+ | data = meta.replace(' | ||
+ | if data in datas: | ||
+ | commands.append(command.format(dir + meta, dir + data)) | ||
+ | else: | ||
+ | print(' | ||
+ | return False | ||
+ | commands = ACTIVATE + SEP.join(commands) | ||
+ | |||
+ | with open(NEWWIKI, | ||
+ | result = subprocess.call(commands, | ||
+ | if result == 0: | ||
+ | print(' | ||
+ | return True | ||
+ | else: | ||
+ | print(' | ||
+ | search_for_phrase(NEWWIKI) | ||
+ | print(' | ||
+ | return False | ||
+ | |||
+ | |||
+ | def delete_files(pattern): | ||
+ | """ | ||
+ | matches = 0 | ||
+ | for root, dirnames, filenames in os.walk(os.path.abspath(os.path.dirname(__file__))): | ||
+ | for filename in fnmatch.filter(filenames, | ||
+ | os.remove(os.path.join(root, | ||
+ | matches += 1 | ||
+ | print(' | ||
+ | |||
+ | |||
+ | def get_bootstrap_data_location(): | ||
+ | """ | ||
+ | command = ACTIVATE + ' | ||
+ | return subprocess.check_output(command, | ||
+ | |||
+ | |||
+ | def get_pygments_data_location(): | ||
+ | """ | ||
+ | command = ACTIVATE + ' | ||
+ | return subprocess.check_output(command, | ||
+ | |||
+ | |||
+ | def get_sitepackages_location(): | ||
+ | """ | ||
+ | command = ACTIVATE + ' | ||
+ | return subprocess.check_output(command, | ||
+ | |||
+ | |||
+ | def create_m(): | ||
+ | """ | ||
+ | if WINDOWS_OS: | ||
+ | with open(' | ||
+ | f.write(':: | ||
+ | else: | ||
+ | with open(' | ||
+ | f.write('# | ||
+ | os.fchmod(f.fileno(), | ||
+ | |||
+ | |||
+ | class Commands: | ||
+ | """ | ||
+ | def __init__(self): | ||
+ | pass | ||
+ | |||
+ | def cmd_quickinstall(self, | ||
+ | """ | ||
+ | if os.path.isdir(' | ||
+ | # keep tox test virtualenvs in sync with moin-env-python | ||
+ | command = '{0} quickinstall.py --FirstCall {1}{2}tox --recreate --notest' | ||
+ | print(' | ||
+ | else: | ||
+ | command = '{0} quickinstall.py --FirstCall' | ||
+ | print(' | ||
+ | with open(QUICKINSTALL, | ||
+ | # we run ourself as a subprocess so we can capture output in a log file | ||
+ | result = subprocess.call(command, | ||
+ | print(' | ||
+ | search_for_phrase(QUICKINSTALL) | ||
+ | |||
+ | def cmd_docs(self, | ||
+ | """ | ||
+ | command = ' | ||
+ | print(' | ||
+ | with open(DOCS, ' | ||
+ | result = subprocess.call(command, | ||
+ | print(' | ||
+ | search_for_phrase(DOCS) | ||
+ | if result == 0: | ||
+ | print(' | ||
+ | else: | ||
+ | print(' | ||
+ | |||
+ | def cmd_extras(self, | ||
+ | """ | ||
+ | sp_dir = get_sitepackages_location() | ||
+ | packages = [' | ||
+ | if not WINDOWS_OS: | ||
+ | packages.append(' | ||
+ | installer = 'pip install --upgrade ' | ||
+ | reqs = [' | ||
+ | reqs_installer = 'pip install -r ' | ||
+ | command = ACTIVATE + SEP.join(list(installer + x for x in packages) + list(reqs_installer + x for x in reqs)) | ||
+ | print(' | ||
+ | print(' | ||
+ | with open(EXTRAS, | ||
+ | subprocess.call(command, | ||
+ | print(' | ||
+ | search_for_phrase(EXTRAS) | ||
+ | |||
+ | def cmd_interwiki(self, | ||
+ | """ | ||
+ | print(' | ||
+ | command = '{0} scripts/ | ||
+ | subprocess.call(command, | ||
+ | |||
+ | def cmd_log(self, | ||
+ | """ | ||
+ | |||
+ | def log_help(logs): | ||
+ | """ | ||
+ | print(" | ||
+ | choices = '{0: <16}- {1}' | ||
+ | for log in sorted(logs): | ||
+ | if os.path.isfile(CMD_LOGS[log]): | ||
+ | print(choices.format(log, | ||
+ | else: | ||
+ | print(choices.format(log, | ||
+ | |||
+ | logs = set(CMD_LOGS.keys()) | ||
+ | if args and args[0] in logs and os.path.isfile(CMD_LOGS[args[0]]): | ||
+ | if WINDOWS_OS: | ||
+ | command = 'start {0}' | ||
+ | else: | ||
+ | # .format requires {{ and }} to escape { and } | ||
+ | command = ' | ||
+ | subprocess.call(command, | ||
+ | else: | ||
+ | log_help(logs) | ||
+ | |||
+ | def cmd_new_wiki(self, | ||
+ | """ | ||
+ | command = ' | ||
+ | print(' | ||
+ | make_wiki(command) | ||
+ | |||
+ | def cmd_sample(self, | ||
+ | """ | ||
+ | # load items with non-ASCII names from a serialized backup | ||
+ | command = ' | ||
+ | print(' | ||
+ | success = make_wiki(command, | ||
+ | # build the index | ||
+ | if success: | ||
+ | command = ' | ||
+ | success = make_wiki(command, | ||
+ | # load individual items from contrib/ | ||
+ | if success: | ||
+ | success = put_items() | ||
+ | |||
+ | def cmd_restore(self, | ||
+ | """ | ||
+ | command = '{0} moin index-create -s -i{1} moin load --file %s{1} moin index-build' | ||
+ | filename = BACKUP_FILENAME | ||
+ | if args: | ||
+ | filename = args[0] | ||
+ | if os.path.isfile(filename): | ||
+ | command = command % filename | ||
+ | print(' | ||
+ | make_wiki(command) | ||
+ | else: | ||
+ | print(' | ||
+ | |||
+ | def cmd_import19(self, | ||
+ | """ | ||
+ | if args: | ||
+ | dirname = args[0] | ||
+ | if os.path.isdir(dirname): | ||
+ | command = ' | ||
+ | print(' | ||
+ | make_wiki(command) | ||
+ | else: | ||
+ | print(' | ||
+ | else: | ||
+ | print(' | ||
+ | |||
+ | def cmd_index(self, | ||
+ | """ | ||
+ | if wiki_exists(): | ||
+ | command = ' | ||
+ | print(' | ||
+ | try: | ||
+ | subprocess.call(command, | ||
+ | except KeyboardInterrupt: | ||
+ | pass # eliminates traceback on windows | ||
+ | else: | ||
+ | print(' | ||
+ | |||
+ | def cmd_run(self, | ||
+ | """ | ||
+ | if wiki_exists(): | ||
+ | if WINDOWS_OS: | ||
+ | args += (' | ||
+ | command = ' | ||
+ | try: | ||
+ | subprocess.call(command, | ||
+ | except KeyboardInterrupt: | ||
+ | pass # eliminates traceback on windows | ||
+ | else: | ||
+ | print(' | ||
+ | |||
+ | def cmd_backup(self, | ||
+ | """ | ||
+ | if wiki_exists(): | ||
+ | filename = BACKUP_FILENAME | ||
+ | if args: | ||
+ | filename = args[0] | ||
+ | print(' | ||
+ | else: | ||
+ | print(' | ||
+ | b3 = BACKUP_FILENAME.replace(' | ||
+ | b2 = BACKUP_FILENAME.replace(' | ||
+ | b1 = BACKUP_FILENAME.replace(' | ||
+ | if os.path.exists(b3): | ||
+ | os.remove(b3) | ||
+ | for src, dst in ((b2, b3), (b1, b2), (BACKUP_FILENAME, | ||
+ | if os.path.exists(src): | ||
+ | os.rename(src, | ||
+ | |||
+ | command = ' | ||
+ | with open(BACKUPWIKI, | ||
+ | result = subprocess.call(command, | ||
+ | if result == 0: | ||
+ | print(' | ||
+ | else: | ||
+ | print(' | ||
+ | search_for_phrase(BACKUPWIKI) | ||
+ | print(' | ||
+ | else: | ||
+ | print(' | ||
+ | |||
+ | def cmd_dump_html(self, | ||
+ | """ | ||
+ | if wiki_exists(): | ||
+ | print(' | ||
+ | command = ' | ||
+ | with open(DUMPHTML, | ||
+ | result = subprocess.call(command, | ||
+ | if result == 0: | ||
+ | print(' | ||
+ | else: | ||
+ | print(' | ||
+ | # always show errors because individual items may fail | ||
+ | print(' | ||
+ | search_for_phrase(DUMPHTML) | ||
+ | else: | ||
+ | print(' | ||
+ | |||
+ | def cmd_css(self, | ||
+ | """ | ||
+ | # Note: we use / below within file paths; this works in Windows XP, 2000, 7, 8, 10 | ||
+ | bootstrap_loc = get_bootstrap_data_location().strip() + '/ | ||
+ | pygments_loc = get_pygments_data_location().strip() + '/ | ||
+ | modernized_loc = ' | ||
+ | basic_loc = ' | ||
+ | |||
+ | print(' | ||
+ | command = 'cd {0}{1}stylus --include {2} --include-css --compress < theme.styl > ../ | ||
+ | result = subprocess.call(command, | ||
+ | if result == 0: | ||
+ | print(' | ||
+ | else: | ||
+ | print(' | ||
+ | # stylus adds too many blank lines at end of modernized theme.css, fix it by running coding_std against css directory | ||
+ | command = ' | ||
+ | result = subprocess.call(command, | ||
+ | if result != 0: | ||
+ | print(' | ||
+ | |||
+ | print(' | ||
+ | if WINDOWS_OS: | ||
+ | data_loc = ' | ||
+ | else: | ||
+ | data_loc = ' | ||
+ | include = ' | ||
+ | command = 'cd {0}{1}lessc {2} theme.less ../ | ||
+ | result = subprocess.call(command, | ||
+ | if result == 0: | ||
+ | print(' | ||
+ | else: | ||
+ | print(' | ||
+ | |||
+ | def cmd_tests(self, | ||
+ | """ | ||
+ | print(' | ||
+ | command = ' | ||
+ | result = subprocess.call(command, | ||
+ | print(' | ||
+ | search_for_phrase(TOX) | ||
+ | |||
+ | def cmd_coding_std(self, | ||
+ | """ | ||
+ | print(' | ||
+ | command = '%s scripts/ | ||
+ | subprocess.call(command, | ||
+ | |||
+ | # not on menu, rarely used, similar code was in moin 1.9 | ||
+ | def cmd_dist(self, | ||
+ | """ | ||
+ | print(' | ||
+ | self.cmd_del_wiki(*args) | ||
+ | command = '{0} setup.py sdist' | ||
+ | with open(DIST, ' | ||
+ | result = subprocess.call(command, | ||
+ | print(' | ||
+ | search_for_phrase(DIST) | ||
+ | if result == 0: | ||
+ | print(' | ||
+ | else: | ||
+ | print(' | ||
+ | |||
+ | def cmd_del_all(self, | ||
+ | """ | ||
+ | self.cmd_del_orig(*args) | ||
+ | self.cmd_del_pyc(*args) | ||
+ | self.cmd_del_rej(*args) | ||
+ | self.cmd_del_wiki(*args) | ||
+ | |||
+ | def cmd_del_orig(self, | ||
+ | """ | ||
+ | delete_files(' | ||
+ | |||
+ | def cmd_del_pyc(self, | ||
+ | """ | ||
+ | delete_files(' | ||
+ | |||
+ | def cmd_del_rej(self, | ||
+ | """ | ||
+ | delete_files(' | ||
+ | |||
+ | def cmd_del_wiki(self, | ||
+ | """ | ||
+ | command = ' | ||
+ | if wiki_exists(): | ||
+ | print(' | ||
+ | with open(DELWIKI, | ||
+ | result = subprocess.call(command, | ||
+ | if result != 0: | ||
+ | print(' | ||
+ | # destroy wiki even if backup fails | ||
+ | if os.path.isdir(' | ||
+ | shutil.rmtree(' | ||
+ | shutil.rmtree(' | ||
+ | if os.path.isdir(' | ||
+ | shutil.rmtree(' | ||
+ | if os.path.isdir(' | ||
+ | shutil.rmtree(' | ||
+ | print(' | ||
+ | else: | ||
+ | print(' | ||
+ | |||
+ | |||
+ | class QuickInstall: | ||
+ | |||
+ | def __init__(self, | ||
+ | self.dir_source = source | ||
+ | base, source_name = os.path.split(source) | ||
+ | executable = os.path.basename(sys.executable).split(' | ||
+ | venv = os.path.join(base, | ||
+ | venv = os.path.abspath(venv) | ||
+ | venv_home, venv_lib, venv_inc, venv_bin = virtualenv.path_locations(venv) | ||
+ | self.dir_venv = venv_home | ||
+ | self.dir_venv_bin = venv_bin | ||
+ | |||
+ | def __call__(self): | ||
+ | self.do_venv() | ||
+ | self.do_helpers() | ||
+ | self.do_install() | ||
+ | self.do_catalog() | ||
+ | sys.stdout.write(" | ||
+ | |||
+ | def do_venv(self): | ||
+ | virtualenv.create_environment(self.dir_venv) | ||
+ | |||
+ | def get_pip_version(self): | ||
+ | """ | ||
+ | command = ACTIVATE + 'pip --version' | ||
+ | pip_txt = subprocess.check_output(command, | ||
+ | # expecting pip_txt similar to "pip 1.4.1 from / | ||
+ | pip_txt = pip_txt.decode().split() | ||
+ | if pip_txt[0] == ' | ||
+ | pip_version = [int(x) for x in pip_txt[1].split(' | ||
+ | return pip_version | ||
+ | else: | ||
+ | sys.exit(" | ||
+ | |||
+ | def do_install(self): | ||
+ | pip_version = self.get_pip_version() | ||
+ | args = [ | ||
+ | os.path.join(self.dir_venv_bin, | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | self.dir_source, | ||
+ | ] | ||
+ | if pip_version >= [9, 0]: | ||
+ | args += [' | ||
+ | subprocess.check_call(args) | ||
+ | |||
+ | def do_catalog(self): | ||
+ | subprocess.check_call(( | ||
+ | os.path.join(self.dir_venv_bin, | ||
+ | os.path.join(self.dir_source, | ||
+ | ' | ||
+ | # needed in case user runs quickinstall.py with a cwd other than the repo root | ||
+ | ' | ||
+ | )) | ||
+ | |||
+ | def create_wrapper(self, | ||
+ | """ | ||
+ | target = os.path.join(self.dir_venv_bin, | ||
+ | with open(filename, | ||
+ | f.write(':: | ||
+ | |||
+ | def do_helpers(self): | ||
+ | """ | ||
+ | create_m() | ||
+ | if WINDOWS_OS: | ||
+ | # windows commands are: activate | deactivate | ||
+ | self.create_wrapper(' | ||
+ | self.create_wrapper(' | ||
+ | else: | ||
+ | # linux commands are: source activate | deactivate | ||
+ | if os.path.exists(' | ||
+ | os.unlink(' | ||
+ | os.symlink(os.path.join(self.dir_venv_bin, | ||
+ | |||
+ | |||
+ | if __name__ == ' | ||
+ | # create a set of valid menu choices | ||
+ | commands = Commands() | ||
+ | choices = set() | ||
+ | names = dir(commands) | ||
+ | for name in names: | ||
+ | if name.startswith(' | ||
+ | choices.add(name) | ||
+ | args = sys.argv[:] | ||
+ | |||
+ | if len(args) > 2 and args[-1] == ' | ||
+ | # m and m.bat have trailing --help so " | ||
+ | # if user did "./m < | ||
+ | args = args[:-1] | ||
+ | |||
+ | if (os.path.isfile(' | ||
+ | # user keyed " | ||
+ | print(help) | ||
+ | |||
+ | else: | ||
+ | if not (os.path.isfile(' | ||
+ | # user is running " | ||
+ | create_m() | ||
+ | command = getattr(commands, | ||
+ | # run this same script (quickinstall.py) again in a subprocess to create the virtual env | ||
+ | command() | ||
+ | # a few success/ | ||
+ | print(' | ||
+ | |||
+ | elif args == [' | ||
+ | # user keyed "./m quickinstall" | ||
+ | command = getattr(commands, | ||
+ | # run this same script (quickinstall.py) again in a subprocess to recreate the virtual env | ||
+ | command() | ||
+ | |||
+ | else: | ||
+ | if args == [' | ||
+ | # user keyed " | ||
+ | # run this same script (quickinstall.py) again in a subprocess to create the virtual env | ||
+ | command = getattr(commands, | ||
+ | command() | ||
+ | |||
+ | elif args == [' | ||
+ | # we are in a subprocess call after " | ||
+ | orig_stdout = sys.stdout | ||
+ | orig_stderr = sys.stderr | ||
+ | with open(QUICKINSTALL, | ||
+ | sys.stdout = messages | ||
+ | sys.stderr = messages | ||
+ | QuickInstall(os.path.dirname(os.path.realpath(args[0])))() | ||
+ | sys.stdout = orig_stdout | ||
+ | sys.stderr = orig_stderr | ||
+ | |||
+ | else: | ||
+ | # we have some simple command like "./m css" that does not update virtualenv | ||
+ | choice = ' | ||
+ | choice = choice.replace(' | ||
+ | if choice in choices: | ||
+ | choice = getattr(commands, | ||
+ | choice(*args[2: | ||
+ | else: | ||
+ | print(help) | ||
+ | print(' | ||
+ | </ | ||
+ | </ | ||
+ | |||
+ | ==== インストール ==== | ||
+ | **quickinstall.py** を実行する。\\ | ||
+ | |||
+ | **Linux**\\ | ||
+ | <WRAP prewrap 100%> | ||
+ | < | ||
+ | $ python3 quickinstall.py | ||
+ | </ | ||
+ | </ | ||
+ | <WRAP prewrap 100% result> | ||
+ | < | ||
+ | Running quickinstall.py... output messages redirected to m-quickinstall.txt | ||
+ | |||
+ | Searching m-quickinstall.txt, | ||
+ | |||
+ | 83 | ||
+ | 119 Successfully installed Babel-2.7.0 Flask-1.1.1 Flask-Babel-0.12.2 Flask-Caching-1.7.2 Flask-Script-2.0.6 Flask-Theme-0.3.4 Jinja2-2.10.1 Markdown-3.1.1 MarkupSafe-1.1.1 Werkzeug-0.15.5 XStatic-1.0.2 XStatic-AnyWikiDraw-0.14.2 XStatic-Bootstrap-3.1.1.2 XStatic-CKEditor-3.6.4.0 XStatic-Font-Awesome-4.7.0.0 XStatic-JQuery.TableSorter-2.14.5.1 XStatic-Pygments-2.2.0.1 XStatic-TWikiDraw-moin-2004.10.23.2 XStatic-autosize-1.17.2.1 XStatic-jQuery-3.3.1.1 XStatic-jQuery-File-Upload-4.4.2 XStatic-svg-edit-moin-2012.11.27.1 blinker-1.4 chardet-3.0.4 click-7.0 docutils-0.15.2 emeraldtree-0.10.0 flatland-0.9.1 itsdangerous-1.1.0 moin passlib-1.7.1 pdfminer3-2018.12.3.0 pycryptodome-3.8.2 pygments-2.4.2 pytz-2019.2 setuptools-41.0.1 six-1.12.0 sortedcontainers-2.1.0 whoosh-2.7.4 | ||
+ | 131 Successfully created or updated venv at / | ||
+ | |||
+ | > > > Type " | ||
+ | </ | ||
+ | </ | ||
+ | |||
+ | **Windows**\\ | ||
+ | <WRAP prewrap 100%> | ||
+ | < | ||
+ | > python3 quickinstall.py | ||
+ | </ | ||
+ | </ | ||
+ | <WRAP prewrap 100% result> | ||
+ | < | ||
+ | Running quickinstall.py... output messages redirected to m-quickinstall.txt | ||
+ | |||
+ | Searching m-quickinstall.txt, | ||
+ | |||
+ | 139 Successfully installed Babel-2.9.1 Flask-1.1.4 Flask-Babel-2.0.0 Flask-Caching-1.10.1 Flask-Script-2.0.6 Flask-Theme-0.3.5 Jinja2-2.11.3 Markdown-3.3.4 MarkupSafe-2.0.1 Werkzeug-1.0.1 XStatic-1.0.2 XStatic-AnyWikiDraw-0.14.2 XStatic-Bootstrap-3.1.1.2 XStatic-CKEditor-3.6.4.0 XStatic-Font-Awesome-4.7.0.0 XStatic-JQuery.TableSorter-2.14.5.2 XStatic-Pygments-2.9.0.1 XStatic-TWikiDraw-moin-2004.10.23.2 XStatic-autosize-1.17.2.1 XStatic-jQuery-3.5.1.1 XStatic-jQuery-File-Upload-10.31.0.1 XStatic-svg-edit-moin-2012.11.27.1 blinker-1.4 chardet-4.0.0 click-7.1.2 docutils-0.17.1 emeraldtree-0.10.0 feedgen-0.9.0 flatland-0.9.1 greenlet-1.1.0 itsdangerous-1.1.0 lxml-4.6.3 moin passlib-1.7.4 pdfminer3-2018.12.3.0 pycryptodome-3.10.1 pygments-2.9.0 python-dateutil-2.8.1 pytz-2021.1 six-1.16.0 sortedcontainers-2.4.0 sqlalchemy-1.4.17 whoosh-2.7.4 | ||
+ | 143 c: | ||
+ | 144 | ||
+ | 154 Successfully created or updated venv at C: | ||
+ | Quickinstall run time (h:mm:ss) 0:02:47 | ||
+ | |||
+ | > > > Type " | ||
+ | </ | ||
+ | </ | ||
+ | ^ ディレクトリ | ||
+ | | + ^ moin || moin2 ソースコード | ||
+ | |%%|%%| + | quickinstall.py | ||
+ | |%%|%%| + | m.bat | menu バッチ | | ||
+ | | + ^ moin-venv-python || moin2 仮想環境 | ||
+ | |%%|%%| + | Include | ||
+ | |%%|%%| + | Lib | | | ||
+ | |%%|%%| + | Scripts | ||
+ | |||
+ | menu を実行する。\\ | ||
+ | **Linux, PowerShell**\\ | ||
+ | <WRAP prewrap 100%> | ||
+ | <code powershell> | ||
+ | $ ./m | ||
+ | </ | ||
+ | </ | ||
+ | |||
+ | コマンドプロンプト\\ | ||
+ | < | ||
+ | > m | ||
+ | </ | ||
+ | </ | ||
+ | <WRAP prewrap 100% result> | ||
+ | <code powershell> | ||
+ | |||
+ | usage: "m < | ||
+ | |||
+ | quickinstall | ||
+ | extras | ||
+ | docs create moin html documentation (requires extras) | ||
+ | interwiki | ||
+ | log < | ||
+ | |||
+ | new-wiki | ||
+ | sample | ||
+ | restore * | ||
+ | import19 < | ||
+ | |||
+ | run * run built-in wiki server *options (--port 8081) | ||
+ | backup * roll 3 prior backups and create new backup *option, specify file | ||
+ | dump-html * | ||
+ | index | ||
+ | |||
+ | css run lessc to update basic theme CSS files | ||
+ | tests * run tests, log output (-v -k my_test) | ||
+ | coding-std | ||
+ | |||
+ | del-all | ||
+ | del-orig | ||
+ | del-pyc | ||
+ | del-rej | ||
+ | del-wiki | ||
+ | |||
+ | </ | ||
+ | |||
+ | ==== 空の Wiki を作成 ==== | ||
+ | **Linux, PowerShell**\\ | ||
+ | <WRAP prewrap 100%> | ||
+ | <code powershell> | ||
+ | $ ./m new-wiki | ||
+ | </ | ||
+ | |||
+ | コマンドプロンプト\\ | ||
+ | < | ||
+ | > m new-wiki | ||
+ | </ | ||
+ | </ | ||
+ | |||
+ | <WRAP prewrap 100% result> | ||
+ | <code powershell> | ||
+ | Creating a new empty wiki... | ||
+ | Output messages redirected to m-new-wiki.txt. | ||
+ | Important messages from m-new-wiki.txt are shown below: | ||
+ | |||
+ | Error: attempt to create wiki failed. Do "m log new-wiki" | ||
+ | </ | ||
+ | </ | ||
+ | |||
+ | ==== moin2 の実行 ==== | ||
+ | **Linux**\\ | ||
+ | < | ||
+ | $ ./m run | ||
+ | </ | ||
+ | **Windows**\\ | ||
+ | < | ||
+ | > m run | ||
+ | </ | ||
+ | <WRAP prewrap 100% result> | ||
+ | < | ||
+ | 2019-08-09 18: | ||
+ | 2019-08-09 18: | ||
+ | 2019-08-09 18: | ||
+ | 2019-08-09 18: | ||
+ | 2019-08-09 18: | ||
+ | 2019-08-09 18: | ||
+ | 2019-08-09 18: | ||
+ | 2019-08-09 18: | ||
+ | 2019-08-09 18: | ||
+ | * Serving Flask app " | ||
+ | * Environment: | ||
+ | | ||
+ | Use a production WSGI server instead. | ||
+ | * Debug mode: off | ||
+ | 2019-08-09 18: | ||
+ | </ | ||
+ | </ | ||
+ | [[http:// | ||
+ | {{: | ||
+ | |||
+ | ===== ApacheBench してみる ===== | ||
+ | ローカル簡易実行での ApacheBench の結果。\\ | ||
+ | **Web Server:** Werkzeug/ | ||
+ | **Wiki App:** MoinMoin2\\ | ||
+ | **Lang:** Python 3.7.4\\ | ||
+ | **Web Interface: | ||
+ | <WRAP prewrap 100% result> | ||
+ | < | ||
+ | > ab -n 1000 -c 100 http:// | ||
+ | This is ApacheBench, | ||
+ | Copyright 1996 Adam Twiss, Zeus Technology Ltd, http:// | ||
+ | Licensed to The Apache Software Foundation, http:// | ||
+ | |||
+ | Benchmarking localhost (be patient) | ||
+ | Completed 100 requests | ||
+ | Completed 200 requests | ||
+ | Completed 300 requests | ||
+ | Completed 400 requests | ||
+ | Completed 500 requests | ||
+ | Completed 600 requests | ||
+ | Completed 700 requests | ||
+ | Completed 800 requests | ||
+ | Completed 900 requests | ||
+ | Completed 1000 requests | ||
+ | Finished 1000 requests | ||
+ | |||
+ | |||
+ | Server Software: | ||
+ | Server Hostname: | ||
+ | Server Port: 8080 | ||
+ | |||
+ | Document Path: /Home | ||
+ | Document Length: | ||
+ | |||
+ | Concurrency Level: | ||
+ | Time taken for tests: | ||
+ | Complete requests: | ||
+ | Failed requests: | ||
+ | | ||
+ | Total transferred: | ||
+ | HTML transferred: | ||
+ | Requests per second: | ||
+ | Time per request: | ||
+ | Time per request: | ||
+ | Transfer rate: 48.51 [Kbytes/ | ||
+ | |||
+ | Connection Times (ms) | ||
+ | min mean[+/-sd] median | ||
+ | Connect: | ||
+ | Processing: | ||
+ | Waiting: | ||
+ | Total: | ||
+ | |||
+ | Percentage of the requests served within a certain time (ms) | ||
+ | 50% 35389 | ||
+ | 66% 37042 | ||
+ | 75% 37648 | ||
+ | 80% 38042 | ||
+ | 90% 38871 | ||
+ | 95% 39403 | ||
+ | 98% 39964 | ||
+ | 99% 40189 | ||
+ | | ||
+ | </ | ||
+ | </ | ||
+ | |||
+ | 1 秒間に平均どれくらいのリクエストをさばけるか?\\ | ||
+ | < | ||
+ | Requests per second: | ||
+ | </ | ||
+ | 1リクエストの平均応答時間は?\\ | ||
+ | < | ||
+ | Time per request: | ||
+ | </ | ||
+ | |||
+ | **Web Server:** Apache/ | ||
+ | **Wiki App:** DokuWiki Release 2018-04-22b " | ||
+ | **Lang:** PHP 7.3.3\\ | ||
+ | **Web Interface: | ||
+ | <WRAP prewrap 100% result> | ||
+ | < | ||
+ | abs -n 1000 -c 100 https:// | ||
+ | This is ApacheBench, | ||
+ | Copyright 1996 Adam Twiss, Zeus Technology Ltd, http:// | ||
+ | Licensed to The Apache Software Foundation, http:// | ||
+ | |||
+ | Benchmarking wiki.monsters-g.local (be patient) | ||
+ | Completed 100 requests | ||
+ | Completed 200 requests | ||
+ | Completed 300 requests | ||
+ | Completed 400 requests | ||
+ | Completed 500 requests | ||
+ | Completed 600 requests | ||
+ | Completed 700 requests | ||
+ | Completed 800 requests | ||
+ | Completed 900 requests | ||
+ | Completed 1000 requests | ||
+ | Finished 1000 requests | ||
+ | |||
+ | |||
+ | Server Software: | ||
+ | Server Hostname: | ||
+ | Server Port: 1443 | ||
+ | SSL/TLS Protocol: | ||
+ | Server Temp Key: ECDH P-256 256 bits | ||
+ | TLS Server Name: wiki.monsters-g.local | ||
+ | |||
+ | Document Path: /start | ||
+ | Document Length: | ||
+ | |||
+ | Concurrency Level: | ||
+ | Time taken for tests: | ||
+ | Complete requests: | ||
+ | Failed requests: | ||
+ | Total transferred: | ||
+ | HTML transferred: | ||
+ | Requests per second: | ||
+ | Time per request: | ||
+ | Time per request: | ||
+ | Transfer rate: 315.21 [Kbytes/ | ||
+ | |||
+ | Connection Times (ms) | ||
+ | min mean[+/-sd] median | ||
+ | Connect: | ||
+ | Processing: | ||
+ | Waiting: | ||
+ | Total: | ||
+ | |||
+ | Percentage of the requests served within a certain time (ms) | ||
+ | 50% 2713 | ||
+ | 66% 3079 | ||
+ | 75% 3954 | ||
+ | 80% 5102 | ||
+ | 90% 11795 | ||
+ | 95% 23513 | ||
+ | 98% 33594 | ||
+ | 99% 40993 | ||
+ | | ||
+ | </ | ||
+ | </ | ||
+ | |||
+ | < | ||
+ | Requests per second: | ||
+ | Time per request: | ||
+ | </ | ||
+ | |||
+ | ===== 参考文献 ===== | ||
+ | [[https:// | ||
+ |