カテゴリー別アーカイブ: プログラミング

Ruby on Railsはバージョン管理が大変

Ruby on Railsチュートリアルをやり始めました。開発環境は、Ruby 2.4.0p0[x64-mingw32] + MSYS2です。

ちなみに、これまでRuby 2.4.0ではRailsがインストールできませんでした。nokogiri 1.7.2がRuby 2.3系しか対応していなかったためです。

2017/6/5になってnokogiri 1.8.0がリリースされてようやくインストールできるようになりました。

チュートリアルをやり始めてすぐエラーが出ました。

key must be 32 bytes

ということで、こちらの情報をもとにRailsを5.0.1に変更しました。

でも、これでHerokuにデプロイしてみるとH20(App boot timeout)というエラーになります。起動に時間がかかりすぎているというエラーです。

そこで、Railsのバージョンを5.0.3にしました。すると、普通に起動するようになりました。

Gemfile

gem 'Rails', '5.0.3'

また、rails testでエラーになります。こちらの情報をもとにminitestを5.10.1に指定しました。

minitestの5.10.2でtestが動作しないときに試すこと

これで、とりあえず動いています。

なんだか、少しバージョンが違っただけで動いたり動かなかったりするんですね。

このほかにも、win32consoleを入れた方がいいというメッセージが出て入れてみたりしました。rails testの時に色がつくそうです。

Herokuにデプロイしてみると、Windowsで作られたGemfile.lockは使えませんということで、作り直してくれているようです。RubyをWindowsで使うのはなかなか難しいなと思います。

Django Girls Tutorialをやり終えて

Django Girls Tutorialをやり終えました。

このTutorialの良いところは、Webアプリケーションを作る過程を一通りできることです。

作ったアプリケーションをHerokuで公開するところまで含まれていますので、簡単そうでしたが結構骨が折れました。

実際にやってみないとわからないことが多くありました。

Djangoを触ってみて一番驚いたのは、データの削除をするとき関連するデータまで削除してくれることです。

Tutorialの中で、ブログの記事とコメントを作るのですが、記事を削除すると関連する複数あったコメントまで同時に削除してくれます。データベースを見て確認しました。

自分で関連するコメントを選別して削除する必要はありませんでした。

データベースをきれいに保つには欠かせないと思います。

困った点は、Django Girls Tutorialの日本語版はバージョンが古いらしく、英語版のDjango Girls Tutorial:extensionsをやろうとすると、修正が必要だったことです。ただ、その原因を突きとめる過程で学ぶことが多くありました。

PythonでWebアプリケーションを作りたいとなったときに、Djangoを最初に学ぶには良いTutorialではないかと思います。

Django Girls Tutorial:ExtensionsでNoReverseMatchが出た時の対処法

Django Girls TutorialでDjango Girls Tutorail:ExtensionsのHomework: add more to your website!をやっていた時のこと。

Delete postという項目でpost_remove()という関数を作ってブログを削除するボタンを作りました。

でも、記事の削除はできるのですが、次のようなエラーになりブログのトップに戻りません。

NoReverseMatch at /post/24/remove/
Reverse for 'post_list' not found. 'post_list' is not a valid view function or pattern name.

実は、Django Girls Tutorial:ExtensionsはTutorial本体とはバージョンが違っていて、urls.pyの指定が間違っていました。blog/urls.pyのurlの指定のところで下のようにname='post_list'を付け加えないといけませんでした。

blog/urls.pyの変更前

urlpatterns = [
    url(r'^$', views.post_list),
]

blog/urls.pyの変更後

urlpatterns = [
    url(r'^$', views.post_list, name='post_list'),
]

views.pyファイルの中のredirect('post_list')で指定する値は、urlのnameの値になります。

nameに指定してあるから、redirectを呼んだ時urlがブログのトップページ'/'だとわかり、views.post_list関数が呼ばれます。

日本語版のTutorialをやったあとExtensionsをやっていて原因を見つけるのに時間がかかったので報告しておきます。

英語版をやっている人は問題ないです。

HerokuでGoogle Fontsを使うときはHTTPSが必要

HerokuでDjango Girls Tutorialを作ったときにGoogle Fontsを使ってみました。

ローカルではうまく表示されるのですが、Herokuへデプロイするとなぜかフォントが使われていません。

CSSでstyleを設定する前にGoogle Fontsを読み込まなければならないという情報もあり、stylesheetの読み込み順序を変えてみても、表示は変わりませんでした。なにより、ローカルで動いているのでソースコードが間違っているとは思いにくいです。結局、Herokuで使うときはHTTPSを使わないといけませんでした。

<link href="https://fonts.googleapis.com/css?family=Lobster&subset=latin,latin-ext" rel="stylesheet" type="text/css">

このように、httpsで始まるようにします。

Chromeの開発者ツールで見てみると、一番下のコンソールのところにhttpはHerokuで使えませんと出ていました。見落としていました。

Djangoで静的ファイルが見つからないときの探し方

Djangoを使っていて、CSSなどの静的ファイル(staticファイル)が見つからないときは次のようにするといいです。

css/blog.cssを探す場合、コンソールで次のように打ちます。

python manage.py findstatic --verbosity 2 css/blog.css

すると、次のように表示されます。

Found 'css/blog.css' here:
  /home/hoge/djangogirls/static/css/blog.css
Looking in the following locations:
  /home/hoge/djangogirls/static
  /home/hoge/djangogirls/myvenv/lib/python3.4/site-packages/django/contrib/admin/static

見つかるとFoundで表示してくれますし、見つからなくても探している場所を表示してくれますので確認しやすいと思います。

アプリケーションの場所のstaticディレクトリは、自動で探しにいくようです。

settings.pyのSTATICFILES_DIRでstaticファイルの場所を指定している場合など、場所の確認ができます。

Django Girls Tutorialでmigrateできない

Django Girls TutorialでHerokuへのデプロイをやったときのこと。

heroku run python manage.py migrate

は成功するのですが、

heroku run python manage.py createsuperuserがエラーになりました。

auth_nameが無いといわれます。no such tableだそうです。このようなエラーが出ます。

You have 14 unapplied migration(s). Your project may not work properly until you apply the migrations for app(s): admin, auth, blog, contenttypes, sessions.
Run 'python manage.py migrate' to apply them.

Traceback (most recent call last):
  File "/app/.heroku/python/lib/python3.6/site-packages/django/db/backends/utils.py", line 65, in execute
    return self.cursor.execute(sql, params)
  File "/app/.heroku/python/lib/python3.6/site-packages/django/db/backends/sqlite3/base.py", line 328, in execute
    return Database.Cursor.execute(self, query, params)
sqlite3.OperationalError: no such table: auth_user

原因は、.gitignoreのlocal_settings.pyをsetingとミススペルしていたことでした。

Django Girls Tutorialでは、local_settings.pyがあればローカルのSqlite3を使い、herokuにはこのファイルをpushしないことでPostgreSQLを使うことにしています。

ところが、.gitignoreで指定できなかったため、herokuの方にlocal_settings.pyが転送されて、データベースとしてSqlite3が使われることになってしまいました。migrate時にエラーにならないのですが、データベースファイルができないらしく、tableがないというエラーになっていました。

リモートのファイルのみを消すには、

git rm --cached mysite/local_settings.py

git commit -m "Deleted remote local_settings.py."

git push heroku master

で消すことができました。

デプロイするだけでもいろいろトラブルになるんですね。

HerokuがWindowsで使えないときの対処法

PythonのDjangoに興味があり、Django Girls Tutorialというサイトを見てTutorialをやってみました。

Tutorialでは、Djangoの使い方の紹介とともに、Herokuでアプリを公開することもレッスンに含まれています。

そこで、はまったことを紹介します。

SSHキーの保存場所

heroku keys:add で作成される公開キーの保存場所は、C:/Users/(your name)/.ssh/id_rsa.pubです。MSYS2のMinGW 64-bitを使っていたのですが、MSYS2のホームディレクトリにある~/.ssh/のキーが使われませんでした。

Gitでheroku CLIのものを使う場合

heroku CLIというherokuコマンドを含むtoolがあるのですが、一緒にGitもインストールされます。最初MSYS2のgitをつかってgit push heroku masterしても、usernameとpasswordを聞かれてしまいすんなりとpushできません。

heroku loginでEmailとPasswordを聞かれてログインしているはずですが、認識していません。

結局heroku CLIでインストールされたGitを使うとusernameが聞かれなくなりました。

MSYS2のGitを使う場合は_netrcを.netrcにコピーする

heroku loginで認証したときのユーザー名やパスワードの情報は、ホームディレクトリの~/_netrcというファイルに保存されているようです。

MSYS2のGitを使えないか試してみて、ホームディレクトリの~/_netrc を~/.netrcにコピーすると使えることがわかりました。Heroku CLIのGitも使いたいときは_netをそのままにしておいた方がいいようです。

Pythonのバージョンとpsycopg2のバージョン

MSYS2のPythonは、3.4.5です。Django Girls Tutorialでは3.5.2を指定するよう書かれているので、runtime.txtに書いてgit pushしてみましたが、エラーで動きません。

エラーはpsycopg2をインストールするときに出て、ImportError: No module named 'six'となっています。

remote:            Traceback (most recent call last):
remote:              File "<string>", line 1, in <module>
remote:              File "/tmp/pip-build-799m2cq_/psycopg2/setup.py", line 583, in <module>
remote:                ext_modules=ext)
remote:              File "/app/.heroku/python/lib/python3.5/distutils/core.py", line 148, in setup
remote:                dist.run_commands()
remote:              File "/app/.heroku/python/lib/python3.5/distutils/dist.py", line 955, in run_commands
remote:                self.run_command(cmd)
remote:              File "/app/.heroku/python/lib/python3.5/distutils/dist.py", line 974, in run_command
remote:                cmd_obj.run()
remote:              File "/app/.heroku/python/lib/python3.5/site-packages/setuptools/command/install.py", line 61, in run
remote:                return orig.install.run(self)
remote:              File "/app/.heroku/python/lib/python3.5/distutils/command/install.py", line 551, in run
remote:                self.run_command(cmd_name)
remote:              File "/app/.heroku/python/lib/python3.5/distutils/cmd.py", line 313, in run_command
remote:                self.distribution.run_command(command)
remote:              File "/app/.heroku/python/lib/python3.5/distutils/dist.py", line 974, in run_command
remote:                cmd_obj.run()
remote:              File "/app/.heroku/python/lib/python3.5/site-packages/setuptools/command/install_scripts.py", line 17, in run
remote:                import setuptools.command.easy_install as ei
remote:              File "/app/.heroku/python/lib/python3.5/site-packages/setuptools/command/easy_install.py", line 49, in <module>
remote:                from setuptools.py27compat import rmtree_safe
remote:              File "/app/.heroku/python/lib/python3.5/site-packages/setuptools/py27compat.py", line 7, in <module>
remote:                import six
remote:            ImportError: No module named 'six'
remote:
remote:            ----------------------------------------
remote:          Rolling back uninstall of psycopg2
remote:        Command "/app/.heroku/python/bin/python -u -c "import setuptools, tokenize;__file__='/tmp/pip-build-799m2cq_/psycopg2/setup.py';f=getattr(tokenize, 'open', open)(__file__);code=f.read().replace('\r\n', '\n');f.close();exec(compile(code, __file__, 'exec'))" install --record /tmp/pip-dpg0rw8e-record/install-record.txt --single-version-externally-managed --compile" failed with error code 1 in /tmp/pip-build-799m2cq_/psycopg2/
remote:  !     Push rejected, failed to compile Python app.
remote:
remote:  !     Push failed

仕方がないので、sixをrequirements.txtに加えましたがエラーのままです。

runtime.txtの設定でpython-3.4.5をにしてみると、pipのインストールでエラーになります。No such file or directoryだそうです。
pythonのバージョンを下げるのは得策ではないようです。

remote: -----> Installing requirements with pip
remote:        /app/tmp/buildpacks/779a8bbfbbe7e1b715476c0b23fc63a2103b3e4131eda558669aba8fb5e6e05682419376144189b29beb5dee6d7626b4d3385edb0954bffea6c67d8cf622fd51/bin/steps/pip-install: line 7: /app/.heroku/python/bin/pip: No such file or directory
remote:  !     Push rejected, failed to compile Python app.
remote:
remote:  !     Push failed

pythonを3.6.1にしてもpsycopg2のエラーは変わりませんでした。

Django Girls Tutorialではpsycopg2のバージョンは、2.5.4を指定するようになっています。これを2.6や2.6.1にしてもエラーは変わりませんでした。

いろいろ試してみて結局psycopg2のバージョンを2.7.1にあげることでデプロイが成功しました。pythonのバージョンは、3.5.2と3.6.1のどちらでもよかったです。

requirements.txt

dj-database-url==0.4.2
Django==1.11
gunicorn==19.7.1
pytz==2017.2
whitenoise==3.3.0
psycopg2==2.7.1

Pythonを始めると、virutalenvやvenvといった仮想環境を使ってモジュールのバージョン管理をすることが推奨されていますが、バージョンが合わないとアプリケーションが動かなくなることが納得できました。

Herokuがうまく動かないときの情報が検索してもあまり出てこないので本当に困りました。

MSYS2でansibleを使うときの訂正とpythonのvirtualenvとvenv

MSYS2でansibleを使うときは32bit版ではなくて、インストールするパッケージがmsysのpythonであることが必要でした。
以前の記事を訂正しました。

pythonのバージョンを管理する、python3のvenvやpython2のvirutalenvも、msys用のpythonだと動きますがMinGW用のpythonだと動きません。

スタートメニューのMSYS2 MinGW 32-bitや、MSYS2 MinGW 64-bitのコンソールでは、MinGW用のpythonがインストールしてあるとそちらが優先的に実行されてしまうので注意してください。

msys用のpythonはpipが用意されていませんので、get-pip.pyをcurlでインストールします。

python2の場合、pipでvirtualenvをインストールします。そのうえで-m virtualenvでモジュールを指定して実行します。適当な名前myvenvを指定すると、myvenv/bin/以下にpythonやpipがコピーされます。activateをbashに読み込ませると開発環境が変わります。

カッコつきで(myvenv)のように表示されるとOKです。

deactivateで元に戻ります。

$ pacman -S python2

$ curl -kL https://bootstrap.pypa.io/get-pip.py | python2
$ pip install virtualenv

$ mkdir test
$ cd test
$ python2 -m virtualenv myvenv
$ source myvenv/bin/activate

(myvenv)

$ deactivate

python3をpython2と同居させる場合、pipコマンドをpython2のようにインストールすると、/usr/bin/pipが上書きされてしまいます。
そのため、venvというモジュールを使ってローカルのフォルダにpip関係のモジュールを入れて隔離したほうがいいです。

python2は、virtualenvをpipでインストールしないといけないので、グローバルにインストールするしかないです。

適当な名前myvenvを指定してpython3 -m venvを実行するとpython3の実行ファイルとpipがコピーされて使えるようになります。

$ pacman -S python

$ mkdir python3test
$ cd python3test
$ python3 -m venv myvenv
$ source myvenv/bin/activate

(myvenv)

$ deactivate

python2とpython3でpipをインストールすると、pipは後にインストールしたほうになります。先にインストールした方は、pip2もしくはpip3で指定しないといけないです。

混在するのはよくないので、pipはpython2のみでインストールし、python3は-m venvで仮想環境を作ったときに自動でインストールされるpipを使うのがよいです。

最近開発されたハイパーバイザー

PhoronixというニュースサイトでBareflankというハイパーバイザーが開発されていることを知りました。

調べていくと、最近いろいろなハイパーバイザーが開発されているようです。今回はそれを紹介します。

ハイパーバイザー

Bareflank

セキュリティーなどに応用するためのプロトタイプを目的とする。C++、STLで書かれている。ユニットテストが完備されていて、Coveralls、Travis CI、Astyleが使われていて、Coverity、Clang Tidy、Google's Sanitizersといったところでコードを分析している。

サポートするのは、SandyBrdge以降のCPU。
ホストOSは、
Ubuntu 16.10
Debian Stretch
Fedora 25, 24
OpenSUSE Leap 42.2
Windows 10
Windows 8.1

少しソースコードを見ると、WindowsホストではCygwinでカーネルドライバーを作るようになっていたり、self signをできるようにしていたりと本格的です。

シンプルなハイパーバイザーを目指しているようです。機能を拡張する方法があるようで、次の2つが挙げられています。

Extended APIs

BareflankにVPIDとかMSR bitmapにアクセスするためのAPIなどを提供するもの。

Hyperkernel

他の人が自分のハイパーバイザーを開発できるように、Bareflankのサポートソフトとして開発されている。

MoRE

Windows 7 32-bit で、CPUコアは1、メモリ2GBで動作。WinDDKを使っている。3年前に開発が止まっているようです。

SimpleVisor

Intel x64/EM64T VT-xで動く、シンプルなハイパーバイザー。アセンブリコードは10行、ホストのハイパージャックとアンハイパージャックをサポート。ホストの状態を仮想化できるそうです。EPTとVPIDをサポート。WindowsとUEFI環境で動くそうです。Cのコードは500行、総コード数1700行だとか。

VisualStudio 2015 Update 3で作られる。ミニマルなハイパーバイザーを目指しているそうです。

HyperPlatform

Intel VT-x上でのハイパーバイザー。rootkitや、侵入検知システム、Windowsカーネルのリバースエンジニアリングを目的とする。

Visual Studio Community 2015 Update 3、Windows SDK、Windows Driver Kitで作られる。

ksm

Cで書かれた軽量なx64ハイパーバイザー。WindowsとLinuxホストサポート。WindowsではMinGWを使っています。

まとめ

どれもゲストOSを動かすというより、セキュリティ分野での応用を目指しているようです。CPUのVT-x機能を使う方法など、勉強したい方にはコードが簡単でいいのではないかと思います。VirtualBox、Xen、KVMといったプログラムのコードは複雑ですので。

Ubuntu 16.04をインストールしてからPHPのデバッグができるまで

Ubuntu 16.04上でPHPのデバッグができる環境を整えました。手順をまとめます。

Apache2のインストール

まずはApache2のインストールから。

$ sudo apt install apache2
$ sudo a2enmode userdir

a2enmodeでuserdirを有効にします。これで、ホームディレクトリのpublic_htmlディレクトリを公開できるようになります。作ったディレクトリが/home/hoge/public_htmlだと、

http://localhost/~hoge/で、public_html以下が公開されます。

PHPのインストール

次は、PHPのインストール。

$ sudo apt install php libapache2-mod-php

/etc/apache2/mods-available/php7.0.confのphp_admin_flag engine Offをコメントアウト。これで、上で設定したpublic_html内でPHPが使えるようになります。

MySQLのインストール

次にMySQLのインストール。

$ sudo apt install mysql-server mysql-client

実は、最初mariadb-serverとmariadb-clientをインストールしたのだけれど、rootのパスワードが設定されずアクセスできませんでした。バグのようなのでMySQLに変更しました。

ところが、MariaDBをアンインストールして、MySQLをインストールしようとしてもエラーでできません。こちらの情報に従って完全に設定ファイルを削除した後でインストールできました。

Uninstall MySQL completely

PDOのインストール

PHPからMySQLにアクセスするPDOをインストールします。

$ sudo apt install php-mysql

$ sudo service apache2 restart

上述のようにuserdirを使える状態で、/home/hoge/public_html/index.phpに

<?php
phpinfo();

と書いたファイルを作って、http://localhost/~hoge/でアクセスして、PDOのところにmysqlとドライバが表示されていればOKです。

Javaをインストール

PHPのデバッグにNetBeansを使えればと思い、Javaをインストール。

$ sudo apt-add-repository ppa:webupd8team/java
$ sudo apt-get update
$ sudo apt install oracle-java8-installer

NetBeansをインストール

NetBeansは、PHPを使えるものをダウンロードしてインストールしました。

$ sudo sh ./netbeans-8.1-php-linux.sh

インストール先は、/usr/localではなくてホームディレクトリの中にしました。

日本語のインライン変換ができないときは、以下のようにFcitxの設定をするとうまくいきます。変換候補が離れたところに表示されるので今一つですけど。

Fcitx tips

xdebugをインストール

NetBeansで、PHPをデバッグするためにxdebugをインストールします。

$ sudo apt install php-xdebug

これでインストールはできるのですが、動かすために設定が必要になります。
xdebug.iniにzend_extensionしか設定されていないので、xdebug.remote_enable=1とxdebug.remote_autostart=1、xdebug.idekey="netbeans-xdebug"の3行を付け加えます。
remote_enableは、NetBeansでデバッグするときに必要になります。htmlからphpを呼び出すときなど、2つのファイルにまたがるときはidekeyが必要になります。
、remote_autostartは、後述するVisual Studio Codeでデバッグするときに必要になりました。
/etc/php/7.0/mods-available/xdebug.ini

zend_extension=xdebug.so
xdebug.remote_enable=1
xdebug.remote_autostart=1
xdebug.idekey="netbeans-xdebug"

これで、上述のhttp://localhost/~hoge/にアクセスしてphpinfo()の結果を見ます。xdebugのremote_eanbleがOnになっていればOKです。

もし、Onになっていなければ、/etc/php/7.0/apache2/conf.d/20-xdebug.iniがあるかどうか確認してください。20-xdebug.iniは/etc/php/7.0/mods-available/xdebug.iniのシンボリックリンクになっているはずです。Apache2が設定を読み込んだ場合、phpinfo()のAdditional .ini files parsedという欄に20-xdebug.iniを読んだことが表示されています。

NetBeansでデバッグできることを確認

NetBeansを起動して、ホームディレクトリのpublic_html内にテストプロジェクトを作ります。ソースコードには、phpinfo();を入れます。ブレークポイントを設定して、デバッグを開始。ブレークできれば成功です。

phpinfo()で、xdebugのremote_enableがOnになっていれば、たぶん何も設定しなくても動くと思います。

Visual Studio Codeをインストール

せっかくなので、Visual Studio Codeをインストールしてみます。

code_1.4.0-1470329130_amd64.debをダウンロードして、Gnome ファイルから右クリックして「ソフトウェアのインストールで開く」でインストールしました。

Visual Studio技術情報にある、Visual Studio Code Preview ファースト ステップ ガイド (PDF: 5.9 MB)をダウンロードしてみると、インストールや簡単な使い方が載っています。日本語で読めます。

Ubuntuの場合、ターミナルでcodeと打つと起動します。

PHPのextensionをインストールします。左側のビューバーの上から5番目にある拡張機能を選択。ボックスにPHPを打ち込んでextensionを検索します。

PHP DebugとPHP,Perl,Asm,Bash Code Formatをインストールしました。コードのフォーマッタは、PHP Code Formatもあるのですが、PHPのファイルで?>で閉じるとタブがスペースに変換されなかったり、8カラムになったり不具合がありました。PHP Debugのほうが、xdebugを使うのに重要です。

あとは、コードの中にブレークポイントを設定して、左のビューバーの4番目のデバッグのモードに切り替えます。左上のStart Debuggingという緑色のボタンを押してからブラウザでファイルをアクセスしてみるとブレークします。NetBeansと違って手動でサイトにアクセスしないと勝手にデバッグが始まらないです。エディターと統合環境の違いかなと思います。

もし動かないときは、phpinfo()のxdebugの欄でremote_enableがOnになっていること、remote_autostartがOnになっていることを確認しましょう。

実際にVisual Studio Codeでデバッグしてみましたが、1度フリーズした他は快適に使えました。ソースコードのオートフォーマットなどはNetBeansの方が細かく設定できていいですけれど、高機能なエディタと思えば、デバッグもできるしいいかなと思いました。

ただ、Intellisenseは動いているのですが、よい候補があまり出てこなくてコード補完はあまり使えませんでした。ちょっと残念。