Многопоточная компрессия и tar

Сколько можно? :) Ядер все больше и больше, а

$ tar -cjf /mnt/_backup/`date '+%Y-%m-%d_%H-%M-%S'`.tbz2 /home

как работал в один поток, так и работает.

Есть два многопоточных решения:

  • pbzip2 — параллельный bzip
  • pigz — параллельный gzip
$ tar -c /home | pbzip2 -vc -9 -p7 /mnt/_backup/`date '+%Y-%m-%d_%H-%M-%S'`.tbz2

Опцией -p# можно управлять количеством ядер, которые будет использовать архиватор. Нормально — это N-1.

Аналогично и для gzip

$ tar -c /home | pigz -vc -9 -p7 /mnt/_backup/`date '+%Y-%m-%d_%H-%M-%S'`.tbz2

С удивлением открыл для себя, что — в bash по дефолту означает stdout. И

$ tar -cf - file

будет использовать в качестве файла stdout. :)

Firefox: NS_ERROR_FILE_CORRUPTED

Столкнулся сегодня с этой ошибкой в консоли фокса.

Причина проста: повреждение хранилища localStorage. Подробнее можно посмотреть официальную документацию.

Решается удалением файла

webappsstore.sqlite

.

В коде же это исключение так же следует обрабатывать корректно (чтобы не пугать пользователя).

try {
    setLocalStorageItem(key, value);
} catch(e) {
    if(e.name == "NS_ERROR_FILE_CORRUPTED") {
        showMessageSomehow("Sorry, it looks like your browser storage has been corrupted. Please clear your storage by going to Tools -> Clear Recent History -> Cookies and set time range to 'Everything'. This will remove the corrupted browser storage across all sites.");
    }
}

Странно, но в моем случае чистка всего-всего таки не помогла. Помогло ручное удаление файла.

Разработка на Python с использованием virtualenv

Virtual Environment — полезный инструмент, который позволет держать различные конфигурации зависимостей проектов в разных директориях. Например он решает проблему когда одному приложению требуется версия 1.0 пакета X, а другому — 2.0.

vitrualenv

Главным инструментов будет virtualenv.

$ sudo yum install python-virtualenv

Использование

Создадим окружение

$ cd project_dir
$ virtualenv proj_env

Этими командами мы создадим папку proj_env, которая будет содержать наше новое окружение. В этой папке будет набор скриптов и копия интерпретатора python, который будет использоваться в окружении (окружение использует свой интерпретатор, а не общесистемный).

При создании окружения можно указать, какая версия python нам нужна.

Возможно, что в системе параллельно стоит как python2, так и python3. Выбирать версию при создании окружения мы можем ключем -p. Если ключ не указан, то будет выбрана версия /usr/bin/python.

$ virtualenv -p /usr/bin/python3.4 proj_env

Для того, чтобы попасть в наше новое окружение используем

$ source proj_env/bin/activate

Теперь мы внутри окружения.

Определеить это можно по изменившемуся приглашению:

(proj_env)тут_старое_приглашение_из_$PS1

Все. Мы внутри окружения. Можно ставить зависимости для нашего приложения.

$ pip install flask flask-bootsrap rq rq-scheduler pymysql

Выйти из окружения можно при помощи

$ deactivate

Теперь мы попали обратно в систему с дефолтными интерпретаторами.

Сохранение информации о зависимостях

Опция —no-site-packages отключает использование глобально-установленных пакетов, что может быть полезно (сейчас это дефолтное поведение virtualenv).

Хорошей идей будет сохранить информацию об установленных в окружении пакетов.

{code lang=»shell»]$ pip freeze > requirements.txt[/code]

После развертывание окружения в новой системе можно поднять все пакеты сразу.

$ pip install -r requirements.txt

Не забываем добавить папку окружения в .gitignore.

virtualenverapper

Еще один полезный инструмент (скорее для разработчиков, а не для деплоя), который позволяет обращаться со со множеством окружений и переключаться между ними.

$ sudo yum install python-virtualenvwrapper

Применение

Добавляем в .bashrc

export WORKON_HOME=~/.envs
source /usr/bin/virtualenvwrapper.sh

Теперь можно создавать окружения.

$ mkvirtualenv proj_env

Активировать окружения.

$ workon proj_env

Выходить из окружения можно так же как это делалось в кготом virtualenv.

$ deactivate

Удалять окружения.

$ rmvirtualenv proj_env

При этом все папки окружений будет расположены в одном месте: папке, которая задана через $WORKON_HOME.

Дополнительные команды

Есть несколько дополнительных команд

  • lsvirtualenv — покажет список созданных окружений
  • cdvirtualenv — перейдет непосрественно в папку окружения
  • cdsitepackages — переведет в site-packages выбранного окруженияч
  • lssitepackages — сделает ls для папки site-packages

Посмотреть полный список команд.

autoenv

Утилита позволяет активировать окружение при входе в папку, и деактивировать при выходе.

$ git clone git://github.com/kennethreitz/autoenv.git ~/.autoenv
$ echo 'source ~/.autoenv/activate.sh' >> ~/.bashrc

Tmux — лучшая альтернатива screen

Довольно долго пытался пересесть с GNU Screen на tmux, но вот только сдерживало несколько вещей в нем.
На сайте проекта можно найти описание всех фич, я же опишу лишь те, которые для меня оказались самыми полезными.

  • Улучшенная модель отрисовки (да-да screen периодически подключивал)
  • Содержимое терминала не теряется, когда мып ользуемся редакторами (открыли vim, закрыли, история осталась а месте и можно прокрутить до нее)
  • Конфигурирование на лету

C-b

Ага. Это сочетание клавишь из vim.

Переключим tmux на работу с C-a

set-option -g prefix C-a

Задержка между контрольными клавишами C-b и непосредственным вводом команды (например n).

Решается просто

set -s escape-time 0

Сочетание клавиш для управления tmux внутри tmux

Бывает такое, что приходится внутри tmux запустить вложенную сессию tmux. Значит надо как-то пробросить этой вложенной сессии команды. Например C-a a command

bind-key a send-prefix

Начинаме считать окна с 1, а не 0

Это удобно, так как 0 находится где-то на отшибе. И к нему надо тянуться.

set -g base-index 1

Агрессивный ресайз терминалов

Дефолтно при подключении к сессии нескольких клиентов рамер окна выбирается по размеру самого маленького клиента. Это неинтересно. Поэтому позволим терминалу для каждого клиента иметь собственный размер.

setw -g aggressive-resize on

После завершения команды можно ввести другую команду не нажимая C-b

Для меня эта проблема была самой неприятно. Воспроизвести ее просто: нужно на готом tmux создать два региона.

C-b "

А затем переключаться между ними.

C-b Up Down Up Down

Вы заметите, что нажав один раз C-b, а потом быстро нажимая вверх-вниз окна переключаются.

Это неприятно когда пытаешься переключить вкладку и начать тут же вводить что-то.

За такое поведение отвечает repeat-time

repeat-time time
  Allow multiple commands to be entered without pressing
  the prefix-key again in the specified time milliseconds
  (the default is 500).  Whether a key repeats may be set
  when it is bound using the -r flag to bind-key.  Repeat
  is enabled for the default keys bound to the resize-pane
  command.

Можно отключить repeat для команд переключения между панелями и окнами просто переобъявив команду без флага -r. Например так:

bind-key Up select-pane -U

Но я же предпочитаю эту фичу отключить вовсе.

set-option -g repeat-time 0

Базовый ~/.tmux.conf

# C-b не подходит - так как используется в vim
set-option -g prefix C-a
bind-key C-a last-window

# Начинам нумерацию окон с 1
set -g base-index 1

# Добавляем отзывчивости в реакции на команды
set -s escape-time 0

# Отключаем ожидание дополнительных команд
set-option -g repeat-time 0

# Или можно забиндить команды отдельно отключая repeat только для нужных
#bind-key Up select-pane -U

# Цветовая схема
set -g status-bg black
set -g status-fg white
set -g status-left ""
set -g status-right "#[fg=green]#H"

# Ресайзим содержимое окна индивидуально для каждого клиента
setw -g aggressive-resize on

# Позволим пробрасывать команды внутрь вложенной сессии tmux
# при помощи  C-a a <command>
bind-key a send-prefix

# Мониторинг активности
#setw -g monitor-activity on
#set -g visual-activity on

# Пример использования команды оболочки в статусной строке
#set -g status-right "#[fg=yellow]#(uptime | cut -d ',' -f 2-)"

# Подсвечиваем активное окно
set-window-option -g window-status-current-bg green

За кадром осталось использование tmuxinator для запуска tmux c определенной заранее раскладкой окон.

Ну и еще про настройку можно почитать в Arch-wiki.

Python 3+ и окончания строк в файлах

Столкнулся одного теста, который был перенесен с python 2+ на python 3+.

Тест делал следующее:

скачивал файл через python.requests и сравнивал его с эталонным содержимым на диске (посимвольно).

Выглядело приблизительно так

import requests
import sys
response = requests.get(sys.argv[1])
if response.code == 200:
  with open(sys.argv[2]) as f:
    from_storage = f.read()
    from_web = response.text
    assert from_web == from_storage

Да. Все верно. Этот тест не проходил.

И тут была замечена одна странность: файл на диске содержал последовательность crlf, а в coдержимом from_storage этой последовательности не оказало.

А дело все в том, что в python 3+ было введено соглашение на обработку символов перевода строки. И управление работой осуществляется манипулированием параметром newline.

  • On input, if newline is None, universal newlines mode is enabled. Lines in the input can end in ‘\n’, ‘\r’, or ‘\r\n’, and these are translated into ‘\n’ before being returned to the caller. If it is '', universal newline mode is enabled, but line endings are returned to the caller untranslated. If it has any of the other legal values, input lines are only terminated by the given string, and the line ending is returned to the caller untranslated.
  • On output, if newline is None, any ‘\n’ characters written are translated to the system default line separator, os.linesep. If newline is '', no translation takes place. If newline is any of the other legal values, any ‘\n’ characters written are translated to the given string.

В итоге достаточно было указать newline='' как CRLF появились.

window.location — не всегда оно работает как надо

Если раньше мы долго ругались на проблемы IE, то сейчас на FF и Chrome — ничего особо не поменялось.

На этот раз отличились механизмы работы с хешом в window.location.

Кейс: мы хотим перенаправить пользователя с помощью js на другую страницу.

Что может пойти не так?

Например у нас есть ссылка вида /foo. И логично предположить, что в современном мире мы хотим сохранить хеш (это нужно для angularjs например) чтобы на новой странице отработал нужный функционал.

Что мы делаем

window.location.pathname = '/foo'

Работает.

Но стоит только в ссылку нечаянно попасть хешу #, как поведение браузеров сразу резко меняется.

window.location.pathname='/foo#bar'

Chrome среагирует правильно и отправит нас по ссылке /foo%23bar, а Firefox — нет. У него будет ссылка /foo#bar.

Ниже иллюстрации.

FF: window.location.pathname bugChrome: window.location.pathnameКак видим FF с задачей не справился. И не перекодировал # автоматом.

Баг этот давний — аж 2009го года.

Поэтому внимательно следите за редиректами если у вас есть спецсимволы в урле.

Проще говоря: pathname в FF вседет себя так же, как и href (за мелким исключением вроде сохранения хеша).

Исходники на посмотреть тут.