Intro #

Что это за страничка? Дисклеймер #

Привет! Меня зовут Павел, я программист.

На этой страничке предлагаю вашему вниманию набор личных

в области программирования и не только.

Помимо программирования также интересуют темы:

Я люблю систематизировать знания, для меня лично эта страничка является своеобразной базой знаний (F.A.Q) и записной книжкой. Следую принципу Эйнштейна, “зачем мне что-то запоминать, когда я могу легко посмотреть это в книге”. А ещё знания могут улучшить качество жизни.

На создание странички немного вдохновила эта https://www.reg.ru/coding_standards

Бывает что у меня спрашивают совета по тому или иному вопросу. Специально поэтому на страничке работают якорные ссылки, вместо копирования текста целиком можно скинуть прямую ссылку на соответствующий раздел

Ещё я добавил эту страничку в закладки, во многих случаях она становится отправной точкой для решения каких-то проблем. Т.к. страничка публична, вы можете сделать также ;)

Если вы увидели пустой раздел - значит он в ближайшее время точно будет наполнен.

Предлагаемый список советов не является исчерпывающим.

Как технически работает эта страничка? #

Исходный текст страниц написан на языке Markdown, хранится в git-репозитории и хостится на бесплатной платформе Github Pages

Постоянный адрес странички: https://pavelsr.github.io/my_coding_standarts/

Страница собирается простым генератором сайтов Jekyll, написанным на Ruby

Логика сборки простая и по сути сводится к трём строчкам кода

https://github.com/pavelsr/my_coding_standarts/tree/master/_sections

Для красоты также используются готовые opensource-библиотеки

Как поучаствовать в наполнении? #

Я с удовольствием рассмотрю все замечания и дополнения :)

Присылайте правки в формате pull request сюда

Кстати, для того чтобы предложить правки совсем не обязательно знать git, достаточно отредактировать через браузер соответствующий раздел из папки _sections и выбрать “Create a new branch for this commit and start a pull request” при сохранении изменений. Если для вас это совсем сложно - присылайте правки в свободном формате в Telegram

Идеально, если вы владеете git и можете сами посмотреть как будут выглядеть ваши правки на скомпилированной странице. Как это сделать - расписано тут

Если вы хотите сделать себе аналогичную страничку со своими гайдлайнами - заведите себе аккаунт на Github, перейдите на страничку https://github.com/pavelsr/my_coding_standarts и нажмите справа вверху кнопку “Fork”. Страничке станет доступна на https://<your_username>.github.io/my_coding_standarts/.

За определённую плату могу также настроить такую страничку “под ключ” ;)

Принципы наполнения #

  1. В целях быстрой загрузки страницы минифицирую количество вставленных изображений и использую для изображений/видео внешние ссылки.
  2. Ссылки на разделы внутри статьи по возможности относительные
  3. Тезисы и факты по возможности подтверждать ссылками на первоисточник или более авторитетный источник
  4. По возможности указывать ссылки на готовые docker или lxc контейнеры
  5. Желательно не более 3 уровней вложенности (#, ## и ###)
  6. В папках только подразделы. Обычно подразделы целесообразно создавать по языкам программирования или модулям отдельных фреймворкам (например какие-нить сложные плагины jquery)

Общие вопросы #

Вообще, на большинство вопросов уже есть ответы

Ёмко сформулируйте запрос на английском и поищите на Stackexchange - самое большое сообщество технологических экспертов

Интересные вопросы я добавляю себе в избранное, можете посмотреть там:

Stackoverflow

AskUbuntu

SuperUser

Также рекомендую посмотреть awesome - пользовательские списки отличных opensource инструментов

Если ваш вопрос касается конкретного устройства (телефона, 3G модема, камеры и др.) - поищите на форуме 4PDA

Если вы сисадмин, вам надо настроить какие-то железки или вы технический специалист Фаблаб - взгляните еще сюда (и вообще во все три pinned репозитория профиля)

Как разобраться с ошибкой программного обеспечения? #

Я хочу руководить программистами. Что мне нужно знать? #

Как выбрать технологию для решения конкретной задачи? #

Хочу выучить язык программирования. С чего начать? #

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

Смотрите эту github коллекцию https://github.com/collections/learn-to-code

А еще запомнить принип RTFM :)

Какой язык программирования выбрать первым? #

Как ничего не забывать? #

Рекомендации приложений #

Здесь собираю список дополнительного ПО (преимущественно открытого и бесплатного), которое может быть полезно при разработке и дизайне.

А также частые настройки по разграничению прав пользователей

Мои личные предпочтения как разработчика:

Рекомендуемый кроссплатформенный софт #

И конечно современные браузеры - Firefox, Opera, Яндекс.Браузер, Chrome, Ungoogled Сhrominum, Tor Browser

Only Windows #

Only Linux #

Only Android #

https://anybalance.ru/ - мобильное приложение мониторинг балансов

Плагины для браузеров #

  1. Custom JavaScript for websites
  2. Browsec VPN
  3. JSON Viewer
  4. Lightshot
  5. Web Developer

Рекомендуемые облачные сервисы #

Note: cсылки могут быть партнёрскими :)

https://documents.kontur.ru/ - бесплатное выставление первички: счёт, акт, накладная (аналог есть в тинькофф.бизнес)

https://hrscanner.ru/ - автоматизация тестирования персонала

https://emny.ru/ - поиск сотрудников ВК, с ними работает Леруа Мерлен

Можно поставить на собственный сервер #

Проект Фукционал Docker образ LXC контейнеры
https://nextcloud.com/ файловый сервер    
https://owncloud.org/ файловый сервер    
https://goharbor.io/ docker registry    
https://botpress.io сервер для создания собственных ботов    
https://sentry.io/ система агрегации ошибок    
https://www.freepbx.org/ собственная SIP телефония    
https://phplist.com/ email рассылки, аналог MailChimp    
prometheus.io мониторинг ( аналоги: Zabbix, Nginx, Kibana )    
https://opentracing.io/ трасировщик    
osticket тикетная система (аналог: OTRS, Redmine)    
https://www.limesurvey.org/ опросы    
Odoo CRM/ERP    
Zoneminder видеонаблюдение    
maltego инструмент для анализа данных    
docxtemplater конструктор документов    
DocxJS конструктор документов    
Syndesis opensource аналог Zapier    

VPN #

https://github.com/kylemanna/docker-openvpn

https://github.com/jpetazzo/dockvpn

Сокращалки url #

https://bitly.com

https://git.io/

https://goo.gl - Google, с API и аналитикой

https://t.co - twitter

http://yourls.org/ - можно на свой домен, https://github.com/YOURLS/YOURLS

https://kutt.it/

Типичное конфигурирование ОС #

Раздел для сисадминов

Особенности ОС, которые важно знать

Далее решения типичных задач конфигурирования

Linux #

Определить что замедляет загрузку компьютера #

dmesg
systemd-analyze [critical-chain|blame]

Также можно отключить в /etc/default/grub опции quiet splash и посмотреть вживую что долго грузится.

Лог загрузки можно увидеть в /var/log/boot.log

Если видишь [ TIME ] Timed out waiting for device /dev/disk/by-uuid/CC01-64BD - возможно Windows изменил UID раздела /boot/efi, рекомендуется уточнить через blkid

Добавить привилегии гостевым пользователям: #

1) Сеть, через GUI Network manager: https://askubuntu.com/questions/894750/allow-a-guest-session-wifi-access-with-no-users-logged-in

2) Съемные носители

New user: useradd -G plugdev fablab

sudo usermod -a -G <groupName> userName

sudo usermod -a -G plugdev fablab

sudo usermod -a -G netdev fablab

Либо создать пользователя fablab-user без пароля и добавить все эти привилегии ему

Полная инфа по привилегиям: https://wiki.ubuntu.com/Security/Privileges

Как сделать виртуальную машину доступной для всех пользователей? #

  1. Добавляем нужных пользователей в группу vboxusers
sudo usermod -a -G vboxusers $USER

Посмотреть список групп пользователя можно командной groups $USER

  1. Делаем папку виртуальной машины общей

  2. Заходим в пользователя, оттуда запускаем команду Машина -> Добавить

P.S. Этот вариант расчитан на то, что виртуальную машину одновременно использует только один человек (вообще судя по всему VirtualBox и так сам её блокирует для запуска от других пользователей)

Переключение раскладки в убунту 18.04 #

CTRL+WIN+SPACE

Принтеры Samsung в Linux #

При попытке установить suldr в ubuntu 18.04 d

W: Ошибка GPG: https://www.bchemnet.com/suldr debian InRelease: Следующие подписи не могут быть проверены, так как недоступен открытый ключ: NO_PUBKEY FB510D557CC3E840
E: Репозиторий «https://www.bchemnet.com/suldr debian InRelease» не подписан.
N: Обновление из этого репозитория нельзя выполнить безопасным способом, и поэтому по умолчанию он отключён.
N: Смотрите справочную страницу apt-secure(8) о создании репозитория и настройке пользователя.

и решение, предложенное на форуме (ниже)

sudo apt-get clean            # Remove cached packages
cd /var/lib/apt
sudo mv lists lists.old       # Backup mirror info
sudo mkdir -p lists/partial   # Recreate directory structure
sudo apt-get clean
sudo apt-get update           # Fetch mirror info

не помогает

Также не помогают

sudo apt-key adv --keyserver bchemnet.com --recv-keys FB510D557CC3E840
wget http://www.bchemnet.com/suldr/pool/debian/extra/su/suldr-keyring_1_all.deb
[trusted=yes]

https://mirror.yandex.ru/mirrors/deepin/packages/pool/non-free/s/suldr-keyring/ - зеркало яндекса

sudo wget -O key.deb https://mirror.yandex.ru/mirrors/deepin/packages/pool/non-free/s/suldr-keyring/suldr-keyring_2_all.deb
sudo dpkg -i key.deb

Реверс-инжиниринг #

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

Особенно полезно если в репозитории может лежать неработающий код.

Изучение репозитория #

Показать summary какие расширения файлов есть в папке

find . -type f | perl -ne 'print $1 if m/\.([^.\/]+)$/' | sort -u

TO-DO: показывать рядом с расширениями статистику файлов

https://stackoverflow.com/questions/1842254/how-can-i-find-all-of-the-distinct-file-extensions-in-a-folder-hierarchy

API #

Очень удобный инструмент для документирования API - Swagger

Вначале можно инспектить API через Swagger Inspector, а уже оттуда добавлять в SwaggerHub

Диаграмма вызовов Perl модуля #

Вариант 1 - статический анализ.

Написал отличный хелпер для perl_call_graph

Установка:

sudo curl -L https://bit.ly/perlcghelper -o /usr/local/bin/pcg && sudo chmod +x /usr/local/bin/pcg

Вариант 2 - динамический анализ

Простой вариант - запустить стандартный дебаггер

Сложный вариант (требует запуска скрипта) - вызвать скрипт с опцией -d:NYTProf, затем hytprofhtml и посмотреть packages-callgraph.dot. Бонус этого варианта что покажет ещё и время выполнения каждой функции

CV #

В этом разделе собрана информация о том, как написать хорошее резюме

https://sourcerer.io/ (пример - https://sourcerer.io/pavelsr)

https://github.com/github/personal-website

Bash #

Some helpful scripts

Task 1. Delete all before binlog

/mysql/mysql_dbh/binlog/dbh.000371
/mysql/mysql_dbh/binlog/dbh.000372
/mysql/mysql_dbh/binlog/dbh.000373
sed 's/^.*binlog/binlog/' /diskd/litdb/mysql_dbh/binlog/dbh.index

Изменить оболочку #

chsh

Портабельность #

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

Например из-за этого

#!/usr/bin/env bash

cat without comments

cat httpd.conf | egrep -v "^\s*(#|$)"

Напечатать при помощи cat

cat <<EOF > print.sh
#!/bin/bash
echo \$PWD
echo $PWD
EOF

Вывести рекурсивно список файлов с содержимым #

find -L -type f -name "*.json" | xargs tail -n +1

Хороший, но недостаточно, вывод:

tree
find -L -type f . -exec cat {} +
find -L -type f | xargs cat
find . -type f -printf "%p\n"

Linux #

Требования к разделу: приведенные решения должны работать в любой Linux системе, даже в Busybox

Добавление пользователей #

sudo adduser [--home  DIR] user

Добавить пользователя к группе (полезно в dialout, docker и т.д) #

sudo usermod -aG docker $USER

Авторизация без утомительного ввода пароля каждый раз #

Два варианта:

1) ssh-copy-id id@server

2) sshpass - требует сохранения пароля в явном виде где-нить в текстовом файлике

Генерация ssh ключа #

ssh-keygen -t rsa -b 4096 -C "your_email@example.com"

одновременно выполнить команду через ssh на нескольких машинах #

sudo apt-get install clusterssh

Поиск свободных портов на локальном хосте #

netstat -ntulp | grep LISTEN
netstat -ntulp | grep LISTEN | grep 80
netstat -ntulp | grep LISTEN | grep VirtualBox

Добавление своих команд #

Глобальное решение - симлинк на нужный скрипт в $PATH. Обычно добавляют в /usr/local/bin или в /usr/bin

Например

sudo ln -s /full/path/to/your/file /usr/local/bin/name_of_new_command
sudo ln -s /root/certbot-auto /usr/local/bin/certbot

Для конкретного юзера - редактировать ~/.bashrc

Альтернатива - использование alias (обычно пишутся в .bash_profile)

ln -s $(which <existing_command>) /usr/bin/<my_command>

Узнать куда подключился com порт #

dmesg | grep tty

Постоянное монтирование диска в /etc/fstab #

  1. Посмотреть UUID
sudo blkid
  1. Создать точку монтирования
sudo mkdir /media/windows
  1. Добавить в fstab

Образец

# <file system> <mount point>   <type>  <options>       <dump>  <pass>
UUID=be35a709-c787-4198-a903-d5fdc80ab2f8  /media/nas  ntfs-3g  auto,users,uid=1000,gid=100,dmask=027,fmask=137,utf8  0  0

Другие задачи монтирования и ошибки #

Примонтировать конкретный раздел до перезагрузки #

sudo mount -t auto -v /dev/sdb2 /diskd

Если NTFS система не размонтируется #

Использовать -l и -f опции umount

Сканирование на плохие блоки #

sudo badblocks -vs /dev/sdb2 > badblocks.txt

Изменение дефолтного имени хоста #

sudo nano /etc/hostname
sudo nano /etc/hosts

Узнать публичный IP из консоли #

dig +short myip.opendns.com @resolver1.opendns.com

Оцена места на диске #

Топ 10 самых больших файлов

du -a / | sort -n -r | head -n 10

Либо можно вызвать GUI sudo baobab

Как узнать где какой диск? #

$ hwinfo --block --short
disk:                                                           
  /dev/sdb             KINGSTON SHSS37A
  /dev/sda             Samsung SSD 850

Альтернативы:

lsblk -o name,mountpoint,label,size,fstype,uuid | egrep -v "^loop"
sudo parted -l

Android #

F.A.Q. #

Как запускать две копии приложения стандартными средствами? #

Настройки -> Утилиты -> Параллельные приложения

Альтернативы: сторонние средства - Parallel Space или новый пользователь

Получение root #

Установка twrp #

Установка кастомной прошивки #

Сделать доступными домены localhost на девайсе с USB-отладкой #

Режим модема #

Бесплатная безлимитная раздача интернета #

Apache #

Проверить включенность модулей #

httpd -M | grep -e cgid -e alias -e env_module

Atom #

Быстрые клавиши #

Ctrl+Shift+P - Command Palette

Список полезных плагинов #

https://atom.io/packages/copy-path удобное копирование всего

https://atom.io/packages/git-blame

https://atom.io/packages/structure-view ( плагин от Alibaba, запускается по Сtrl+O, основан на ctags )

https://atom.io/packages/symbols-view ( Генерация: ctags –language-force=Perl -R . )

https://github.com/danielbrodin/atom-project-manager (alt-shift-P, Ctrl+Shift+P + Project Manager: Edit Projects, поддерживает всё что есть в config.cson )

C кодировкой затык т.к. эта функциональность предоставляется плагином

https://atom.io/packages/atomic-management - конфигурационные файлы для проектов (не поддерживает кодировку)

https://atom.io/packages/file-templates - шаблоны файлов

В некоторых случаях рекомендую отключать системный плагин whitespace, потому что https://github.com/atom/atom/issues/4741

Бэкапы #

Показать crontab для всех пользователей

https://stackoverflow.com/questions/134906/how-do-i-list-all-cron-jobs-for-all-users

Блокчейн #

Change blockhain location #

Если вдруг вам по каким-то причинам нужно загрузить весь блокчейн эфира, но не хватает места на диске

#/bin/bash
OLD_PATH="/home/pavel/.ethereum/geth/chaindata"
NEW_PATH="/Volumes/Drive2/Ethereum/"
mkdir -p $NEW_PATH
cp -rpv $OLD_PATH $NEW_PATH
rm -rf $OLD_PATH
ln -s $NEW_PATH $OLD_PATH

or you can make an alias:

alias namecoin='namecoin -datadir=/media/nas/Namecoin'

botpress #

Запуск #

docker run -it -v $(pwd):/botpress/data -p 3000:3000 botpress/server:v11_9_4

CPA #

Рейтинг - https://cpainform.ru/networks/

Самая популярная площадка - https://cityads.com/

Еще хорошие https://actionpay.net и http://ad1.ru/

CRM #

Автоматизация общения с клиентами через СМС и мессенджеры #

Шаблоны писем #

GMail: Настройки -> Расширенные -> Шаблоны ответов -> Включить

При создании нового письма добавится пункт “Шаблоны ответов” а в нём полезный пункт “Сохранить черновик как шаблон”

Cron #

Be aware with 4 things in cron:

1) $ENV variables

Make your own docker-entrypoint.sh to transfer them from user ENV

2) Home dir (don’t forget to make cd in crontab)

3) In production environment you should use cron -f without any tail -f

4) cronjob file must end with newline

Cron в Docker #

Нюансы (что надо помнить чтоб сберечь много времени)

1) Пакет cron во всех debian-based дистрибутивах скомпилирован так что может выводить свой собственный лог ТОЛЬКО в syslog. пруф. Соответственно если речь о сборки Docker-образа то нужно обязательно включать и запускать rsyslog

Чистый лог cron (без вставок с syslog) можно получить только подтюнив настройки syslog - /etc/rsyslog.conf / /etc/rsyslog.d/50-default.conf

imklog также можно отключить за ненадобностью и генерацией лишних ошибок.

2) Запускать cron нужно с помощью systemd. Если вместо service cron start запустить как cron -f -L 15 то работать почему-то не будет :(

Т.е. единственно правильный CMD будет типа такого

command:
        - /bin/bash
        - -c
        - |
            cat cronjob | crontab - && service rsyslog start && service cron start && tail -f /var/log/syslog

Лог-признак того что cron стартанул правильно:

cron_demo_4 | Jul  1 09:21:55 3673956d987a cron[33]: (CRON) INFO (pidfile fd = 3)
cron_demo_4 | Jul  1 09:21:55 3673956d987a cron[35]: (CRON) STARTUP (fork ok)

https://github.com/moby/moby/issues/19616

docker stop command attempts to stop a running container first by sending a SIGTERM signal to the root process (PID 1) in the container. If the process hasn’t exited within the timeout period a SIGKILL signal will be sent.

cron vs crond #

SYNOPSIS
       cron [-f] [-l] [-L loglevel]

DESCRIPTION
       cron is started automatically from /etc/init.d on entering multi-user runlevels.

OPTIONS
       -f      Stay in foreground mode, don't daemonize.

       -l      Enable  LSB compliant names for /etc/cron.d files. This setting, however, does not affect the parsing of files under
               /etc/cron.hourly, /etc/cron.daily, /etc/cron.weekly or /etc/cron.monthly.

       -n      Include the FQDN in the subject when sending mails. By default, cron will abbreviate the hostname.

       -L loglevel
               Tell cron what to log about jobs (errors are logged regardless of this value) as the sum of the following values:

                   1      will log the start of all cron jobs

                   2      will log the end of all cron jobs

                   4      will log all failed jobs (exit status != 0)

                   8      will log the process number of all cron jobs

               The default is to log the start of all jobs (1). Logging will be disabled if levels is set to zero (0). A  value  of
               fifteen (15) will select all options.
/ # crond --help
BusyBox v1.26.2 (2017-11-23 08:40:54 GMT) multi-call binary.

Usage: crond -fbS -l N -d N -L LOGFILE -c DIR

    -f      Foreground
    -b      Background (default)
    -S      Log to syslog (default)
    -l N    Set log level. Most verbose:0, default:8
    -d N    Set log level, log to stderr
    -L FILE Log to FILE
    -c DIR  Cron dir. Default:/var/spool/cron/crontabs

Alpine linux не требует указать юзера в crontab, а Ubuntu требует

echo '* * * * * perl /root/www/insert.pl 2>&1' > /etc/crontabs/root
ln -sf /proc/1/fd/1 /var/log/syslog

curl #

curl - крайне полезный инструмент для отладки HTTP-запросов

Content-type #

Ниже даны примеры запросов для различных Content-type

application/json #

curl -s -X PUT -H "Content-Type: application/json" -d '{"action":"test"}' https://api_user:api_pass@host:port/api/v2/some_method

application/x-www-form-urlencoded #

Заголовок Content-Type в этом случае устанавливать не нужно

curl -s -X POST -d 'globalCity=7700000000000' http://www.220v.test/city/change/

Показать только заголовки #

curl -sD - -o /dev/null

Отключить кеш #

curl -H "Cache-Control: no-cache"

Девайсы #

Xiaomi IP camera #

Страничка, посвященная работе с IP камерами Xiaomi Ants. На мой взляд лучшие IP камеры на рынке по соотношению цена-качество-дизайн.

Тема про камеру на 4PDA

Подключение камеры к нужной WiFi сети #

Кладём скрипт equip_test.sh с вписанными нужными SSID и passw в корневую папку:

#WiFi setter. Created by nfs911 for 4PDA
#!/bin/sh
#################################################
wifi_name="MakerHouse"
wifi_password="fab12shenzhen"
#################################################
sed -i 's/valid1=0/valid1=1/g' /etc/ui.conf
sed -i 's/doreset=1/doreset=0/g' /etc/ui.conf
#rm /etc/wpa_supplicant.conf
#rm /home/wpa_supplicant.conf
echo "ctrl_interface=/var/run/wpa_supplicant
ap_scan=1
network={
ssid=\""$wifi_name"\"
scan_ssid=1
proto=WPA RSN
key_mgmt=WPA-PSK
pairwise=CCMP TKIP
group=CCMP TKIP
psk=\""$wifi_password"\"
}" > /etc/wpa_supplicant.conf
cp /etc/wpa_supplicant.conf /home/wpa_supplicant.conf
sleep 5
#mv "/home/hd1/test/equip_test.sh" "/home/hd1/test/equip_test.sh.old"
rm "/home/hd1/test/equip

Источник

RTSP #

RTSP urls : rtsp://10.132.193.9/ch0.h264 (1280x738) or rtsp://10.132.193.9/ch1.h264 (low quality, 640x386)

Запись: #

VLC #

vlc -vvv rtsp://10.132.193.9/ch1.h264 --sout="#transcode{vcodec=mp4v,vfilter=canvas{width=640,height=386}}:std{access=file,mux=mp4,dst=/data/123.mp4}"

ffmpeg #

ffmpeg -i rtsp://10.132.193.9//ch0.h264 -vcodec copy -an -bsf:v h264_mp4toannexb fl.h264

Github #

Поиск репозитория по темам #

Может быть полезно для поиска популярных opensource проектов к какой-то сфере

https://github.com/search?q=topic%3Atable&type=Repositories

Особенности API #

У API Github очень хорошая стартовая страничка со списком url ресурсов

https://api.github.com/

JQuery #

JQuery Forms #

Получить все значения формы

var c = console.log($('form').serialize());

Получить конкретное значение формы по name

$('#egrn_form').find('input[name="egrn"]').val();

Perl #

#!/usr/bin/env perl

awesome-perl

stackoverflow my favorites

stackoverflow perl tag top

github.com/topics/perl

telegram ru perl chat

https://gh.metacpan.org/ - Люди Perl или проект “GitHub меееts CPAN”

perldoc #

perldoc - документация, созданная разработчиками языка.

Очень рекомендую полазить по двум следующим ссылкам

https://perldoc.perl.org/perlop.html

http://perldoc.perl.org/index-tutorials.html

http://perldoc.perl.org/index-faq.html

Помимо официального браузера (сейчас в стадии beta) у perldoc есть неофициальный - https://perldoc.pl, в нём очень удобно переключаться между одной и той же документацией для разных версий perl, а также давать пермалинки на разделы

Оформление кода (Code style) #

Все перловые файлы должны быть отформатированы с помощью утилиты perltidy.

Все перловые файлы должны быть написаны в соответствии с рекомендациями “Perl Best Practices”.

Самые основные гайдлайны записаны тут - https://perldoc.perl.org/perlstyle.html

Полный список pbp на русском тут, html версия тут

Автоматизированно проверить свой код на соответствие рекомендациям PBP можно при помощи perlcritic

Хорошие обучающие ресурсы #

Learn Perl in about 2 hours 30 minutes - http://qntm.org/files/perl/perl.html

http://modernperlbooks.com/

https://perl.plover.com/

https://www.youtube.com/user/gabor529/videos

Хорошие ресурсы на русском #

https://metacpan.org/pod/POD2::RU

https://ru.perlmaven.com/

https://ebookfoundation.github.io/free-programming-books/free-programming-books-ru.html#perl

https://ivan.bessarabov.ru/blog

Новостные ресурсы #

https://perlweekly.com/

F.A.Q., chunks and snippets #

Как запустить функцию, чъе имя хранится в переменной? #

https://stackoverflow.com/questions/1915616/how-can-i-elegantly-call-a-perl-subroutine-whose-name-is-held-in-a-variable

smartmatch usage #

no warnings 'experimental::smartmatch';
ok ( "11.06.2019" ~~ @x );

Тернарный оператор #

Разберем один возможно неочевидный вывод при конкатенации и тернарном операторе

Пример:

my $str = '';
my $a = 'a';
$a ? $str.="b" : $str.= "c";
print $str;

Вопрос: Почему выводится bc а не b ?

Ответ: всё просто: приоритет оператора .= больше чем у ?:. Получается: ($a ? $str.="b" : $str).= "c"

Правильная запись тернарного оператора должна выглядеть так:

my $days_plus = ( $dow - $dt_min->day_of_week < 0 ) ? ( 7 - $dow ) : ( $dow - $dt_min->day_of_week ) ;

Часто используемые регулярки #

For popular tasks please check Regexp::Common namespace firstly

Работа с копией - /r

use 5.14.0 ;
my $someString = "how do you do this";
say ($someString =~ s/how do/this is how/r) ;

Live replacement:

my $url =~ s/^\/board\/advertisement\/([0-9:]+)\//$1/;

Complex patterns:

my $pattern = '^\s*server_name\s*'.$hash->{server_name};
$hash->{str_from} = firstidx { $_ =~ qr/$pattern/ } @file;

Tested regexp for email:

if ($text_decoded =~ /(\w+@[\w.-]+|\{(?:\w+, *)+\w+\}@[\w.-]+)/) {
        warn $1;
}

Substring until first appearance:

my $string = "hello.world";
my $substring = substr($string, 0, index($string, "."));

rindex() for reverse search

Посмотреть что в @INC #

perl -le 'print for @INC'
perl -e "print qq(@INC)"

From perl script itself:

print $_."\n" foreach (@INC);

Распечатать все переменные окружения которые видит perl в алфавитном порядке #

foreach (sort keys %ENV) {
  print "$_  =  $ENV{$_}\n";
}

Полезные переменные окружения #

PERL5LIB
PERL5OPT=-d
PERLDB_OPTS='NonStop frame=1'

Использование стандартного дебаггера #

Работа с кодировками #

Если включена прагма use utf8, perl хранит внутри себя кодировки в Unicode

use utf8;
...
my $x = $res->decoded_content;
utf8::encode($x); # unicode -> utf8
my $decoded = decode_json $x;

Также можно юзать другие прагмы:

use encoding "cp1251";
binmode(STDOUT, ':encoding(cp1251):bytes');
use open 'IN' => ':encoding(cp1251)', 'OUT' => ':encoding(cp1251)'

Есть ещё классные модули Deep::Encode и Data::Recursive::Encode

Вывести список всех родительских классов #

The @ISA array contains a list of that class’s parent classes, if any источник

Как сдампить ВСЕ параметры функции вместе в именем функции ? #

sub list {
	my ($calendar, $span) = @_;
	warn "".(caller(0))[3]."() : ".Dumper \@_; # return a list, $calendar - first element, $span second

Работа с массивами #

Последний индекс (размерность) массива по его ссылке #

my $a = [ 1, 2, 3 ];
warn $#$a;

Разница между splice и delete #

delete оставляет undef на месте элемента, a splice удаляет со смещением

Работа с хешами #

https://metacpan.org/pod/Sort::HashKeys

https://metacpan.org/pod/Hash::Ordered

https://metacpan.org/pod/Hash::Flatten - может быть полезно для мультиразмерных хешей

Сложные структуры данных #

Фильтрация массива хешей #

Оставить только определённые поля

for my $i (@$part_groups) {
    for my $k ( keys %$i ) {
        delete $i->{$k} if !grep { $k eq $_ } qw/node_id lev2 lev2_title/;
    }
}
for my $j (@$objects) {
    $j = { map { $_ => $j->{$_} } grep { exists $j->{$_} } @{$jsonconfig->{tickets}{fields_to_leave}} };
  }

Работа с именами файлов и путями #

Рекомендую использовать модули Cwd и File::Spec

Примеры:

use Cwd 'abs_path';
use File::Spec;
warn abs_path('this.pl');
warn abs_path(__FILE__);
warn abs_path('a/this.pl'); # doesn't work
use Cwd;
warn getcwd();
warn File::Spec->catfile(getcwd(), 'html/regexp_test_1.html');  # get abs path

Чтение файла в строку #

Хорошее решение - использование File::Slurp

use File::Slurp qw(read_file);
my $text = read_file($url) ;

Передача параметров в модули #

Вариант 1. Передача через конструктор объекта, ->new().

Вариант 2. Передача через параметры use, дальнейшая обработка через функцию import. Функция use обязательно вызывает import

use MyApp prm1 => 'x';
...

package MyApp;
use Data::Dumper;

sub import {
	print "This method will be executed anyway\n";
    my $pkg = shift;
    warn Dumper \@_;  # [ 'prm1', 'x' ];
}

Примеры: Log::Any::Adpater,

Внимание: если хотите сохранить структуру хеша, передавайте как hashref

Вариант 3. Через обязательный вызов какого-либо метода

use MyApp; my $p = MyApp->new; $p->configure

Вариант 4. Через переопределение глобальных переменных модуля. $Data::Dumper::Indent

Как назвать свой модуль? #

https://pause.perl.org/pause/query?ACTION=pause_namingmodules

Как выбрать лучший модуль с cpan ? #

Вначале посмотреть среди core modules: https://perldoc.perl.org/index-modules-A.html

Также можно воспользоваться моим сервисом, который дает возможность сортировать модули по рейтингу: https://github.com/pavelsr/cpanratings-cmp ( источник данных : https://cpanratings.perl.org/csv/all_ratings.csv )

Автоматическая генерация cpanfile #

sudo cpm install -gv App::scan_prereqs_cpanfile
# then run scan-prereqs-cpanfile
scan-prereqs-cpanfile > cpanfile
sudo cpanm --installdeps .

Как запускать тесты? #

В общем случае: prove -lr

с Переопределение функций в тестах

local *LWP::UserAgent::post = sub { ( undef, $url, %params ) = @_; return $resp };

Вариант переопределения через GOTO если данные внутри переопределения не нужны

my $z = \&LWP::UserAgent::get;
*Text::Tmpl2::render = sub {
   ...
   goto &$z;
};

Подсчет покрытия кода тестами #

Using Devel::Cover

Example from Makefile:

docker-cover:
	docker exec zone cover -test -silent -nogcov -make 'prove -l $(file)' -report html
docker-cover-all:
	docker exec zone cover -test -silent -nogcov -report json

Как написать на Perl свою CLI утилиту? #

Есть модули, которые упростят задачу

https://metacpan.org/pod/App::Cmd

https://metacpan.org/pod/App::CLI::Command

Простейшие CGI скрипты #

#!/usr/bin/env perl
use strict;
use warnings;

print "Content-type: text/html\n\n";
foreach my $key (keys %ENV) {
    print "$key --> $ENV{$key}<br>";
}

Вывод версии Perl:

print "Content-type: text/html\n\n";
print $^V;

DBI #

Извлечение списка схем:

$dbh->tables('', '%', '');

Список таблиц в текущей схеме

@t = $dbh->tables(); # с префиксом

Если нужно значения только одной колонки

$dbh->selectcol_arrayref('SELECT node_id FROM Ru_Node ORDER BY node_id');
@result = @{ $dbh->selectall_arrayref($sql, { Slice => {} }) };

Использование SQL::Abstract с DBI

my $table = 'cities';
my $sql = SQL::Abstract->new;
my $query = { code => 'LED' };

my ($stmt, @bind) = $sql->select($table, [ qw/code name country_code/ ], $query);
my $sth = $dbh->prepare($stmt);
$sth->execute(@bind);
warn Dumper $sth->fetchall_arrayref( {} ); # as AoH, with hash Slice

$sth->execute(@bind);
warn Dumper $sth->fetchall_hashref('code'); # as HoH

При помощи https://metacpan.org/pod/DBI#Catalog-Methods пока нельзя получить инфо о количестве записей, только так:

my $count = $conn->selectrow_array("SELECT COUNT(*) FROM $table");
$sth = $dbh->table_info( $catalog, $schema, $table, $type );
# $catalog - нужно оставить пустой строкой
# $schema - если пустая то текущая база, если нет то будут включены еще и другие бд, например information_schema

Вставка хеша на чистом DBI #

sub _insert_hash {
    my ( $self, $table, $field_values ) = @_;
    # return if !defined $field_values;
    return if (!%$field_values);
    my @fields = sort keys %$field_values;
    my @values = @{$field_values}{@fields};
    my $sql    = sprintf "insert into %s (%s) values (%s)", $table, join( ",", @fields ), join( ",", ("?") x @fields );
    # my $sth = $dbh->prepare_cached($sql);
    my $sth = $self->{dbh}->prepare($sql);
    return $sth->execute(@values);
}

```

Логирование #

1) Для логгирования рекомендуется использовать синглтон Log::Any и Log::Any::Adapter::Fille

(последний особенно удобен если одновременно в лог могут писать несколько cron скриптов - по PID можно легко понять какой именно пишет)

2) Log::Any::Adapter может быть только один

3) Чтобы в логе показывались print, warn и die из модулей нужно STDOUT и STDERR перенаправлять в тот же файл что и задан в Log::Any::Adapter::Fille. Log::Any::Adapter::Fil(l)e их автоматически не перехватывают!

В случае локальных игр с докером (не на продакшене) можно делать так

# perl
* * * * * cd /app && perl -Ilib crawler.pl >>/proc/1/fd/1 2>&1
#
use Log::Any::Adapter ( 'Fille', file => '/proc/1/fd/1', log_level => 'debug' );

P.S. use Log::Any::For::Std; чет не работает.

# не перехватывает warn и die
# use Log::Any::Adapter;
# use Log::Any::For::Std;
# Log::Any::Adapter->set('Fille', file => '/app/some.log', log_level => 'debug');

LWP::UserAgent #

Примеры отправки POST запросов при помощи LWP::UserAgent

JSON, как тут https://htaccess.madewithlove.be/api/docs

my $req = HTTP::Request->new( 'POST', 'https://htaccess.madewithlove.be/api/docs' );
$req->header( 'Content-Type' => 'application/json' );
$req->content( encode_json $content[0] );
my $response = $lwp->request($req);    
print $response->decoded_content;

GET c параметрами и декодирование JSON (на примере API Яндекс.Расписаний)

use strict;
use warnings;
use LWP::UserAgent ();
use JSON;
use Data::Dumper::AutoEncode;

my $ua = LWP::UserAgent->new(timeout => 10);

my %params = (
  from => 'c39',
  to => 'c2',
  format => 'json',
  apikey => '366a6609-cf86-43a5-8e61-05c67c752ec4',
  lang => 'ru_RU',
  date => '2019-05-25'
);

my $url = URI->new("https://api.rasp.yandex.net/v3.0/search/");
$url->query_form(%params);
my $response = $ua->get($url); # HTTP::Response

if ($response->is_success) {
    my $h = decode_json( $response->decoded_content);
    warn eDumper $h;
}
else {
    die $response->content;
}

Модули #

Don’t Reinvent Wheel — Не переизобретайте колесо

Не переизобретайте колесо — если подобное колесо уже существует, просто адаптируйте его для своих нужд. Вероятно, для решения данной проблемы уже существует стандартный модуль в дистрибутиве Perl, или модуль из CPAN, или модуль, разработанный другими людьми внутри организации.

Рейтинги #

Список самых популярных модулей - https://metacpan.org/favorite/leaderboard

http://ali.as/top100/index.html - проект CPAN TOP 100 от Adam Kennedy.

Здесь есть четыре рейтинга

1) модули с наибольшим числом зависимостей (Heavy 100)

2) модули от которых зависят больше всех модулей (Valatile 100)

3) самые “падающие” при установке модули по данным с cpantesters.org (Fail 100)

4) (Meta 100)

http://neilb.org/reviews/index.html - обзоры на модули со сходным функционалом

TODO: предложить на обзор Neil Bowers или сделать обзор

URI::Encode::uri_decode vs URI::Escape::uri_unescape

Mojo::DOM vs XML::LibXML

дебаггеры

Публикация модулей #

https://metacpan.org/release/Minilla

https://metacpan.org/pod/Dist::Zilla

Mojolicious #

F.A.Q., chunks and snippets #

Парсинг скачанного файла с помощью Mojo::DOM #

Simulate http requests

use File::Slurp qw(read_file);
my $text = read_file($url) ;
my $dom = Mojo::DOM->new($text);

# Mojo::Message::Response -> Mojo::DOM

my $dom = $c->ua->get('https://rosreestr.net/kadastr/'.$egrn)->res->dom;

CORS

$c->res->headers->access_control_allow_origin('*');

Тест Mojolicius::Lite

# How to test Mojo::Lite apps
# https://groups.google.com/d/msg/mojolicious/-AL3SpkAwu8/gN0feyzS0_8J

use FindBin;
$ENV{MOJO_HOME} = "$FindBin::Bin/../";
require "$ENV{MOJO_HOME}/backruptcy_api.pl";

Сериализация и обработка параметров

my $param_names = $self->req->params->names

for ( allowed_object_query_properties() ) {
    $query->{$_} = $c->param($_) if ( defined $c->param($_) );
}
my $query = $c->req->params->to_hash

Объектно-ориентированное программирование #

https://perldoc.perl.org/perlootut.html RUS

https://perldoc.perl.org/perlobj.html

Moose

http://modernperlbooks.com/books/modern_perl_2016/07-object-oriented-perl.html

https://metacpan.org/pod/distribution/Moose/lib/Moose/Cookbook.pod

https://metacpan.org/pod/distribution/Moose/lib/Moose/Manual/Attributes.pod

Moo

https://perlmaven.com/oop-with-moo

ORM #

Общие рекомендации (best practices) #

get_column #

Если нужны данные только из одной конкретной колонки - используйте get_column;

Пример:

my @curr_cities = map { $_->city_code } $resultset->search( {}, { select => 'city_code' } );

лучше заменить на

my @curr_cities = $resultset->get_column('city_code')->all;

populate #

  1. Если нужно добавить данные - обратите внимание на метод-обёртку populate, возможно запись будет более лакончиной

Пример:

for my $city_code (@to_insert) {
    $resultset->create( { city_code => $city_code } );
}

лучше заменить на

$resultset->populate([[qw(city_code)], map {[$_]} @to_insert);
-in при работе с массивами #

Если вам нужно удалить массив записей по значениям - упростите запись за счёт модификатора -in

Пример:

for my $city_code (@to_delete) {
    $resultset->search( { city_code => $city_code } )->delete_all;
}

лучше заменить на

$resultset->search({city_code => {-in => \@to_delete}})->delete()

Конструирование запросов WHERE #

Если будет OR - значение будет массив Если будет AND - значние хеш

https://metacpan.org/pod/DBIx::Class::ResultSet

https://metacpan.org/pod/DBIx::Class::ResultSet#ATTRIBUTES

https://metacpan.org/pod/distribution/DBIx-Class/lib/DBIx/Class/Manual/Cookbook.pod#SEARCHING

https://metacpan.org/pod/SQL::Abstract#WHERE-CLAUSES

https://metacpan.org/pod/distribution/DBIx-Class/lib/DBIx/Class/Manual/Cookbook.pod#Using-SQL-functions-on-the-left-hand-side-of-a-comparison

WHERE ID >= x

->search_rs({ id => { '>=', $ARGV[0] }});

WHERE status = ? OR status = ? OR status = ?

status => { '=', ['assigned', 'in-progress', 'pending'] };

UPDATE

Если один аргумент

$order->extra_json($extra_json);
$order->update();

Если несколько

$order->update({ extra_json => $extra_json })

Для специальных функций

my %where = ( -and => [
  foo   => 1234,
  \["EXISTS ($sub_stmt)" => @sub_bind],
]);

Yancy #

Quickstart & F.A.Q. #

  1. Создаём Mojo приложение
mojo generate lite_app app.pl
  1. Запускаем БД

Можно из docker-контейнера

  1. Добавляем в app.pl нужный бэкенд
use Mojo::mysql;

# и прописываем его в конфиге
plugin Yancy => {
    backend => { Mysql => Mojo::mysql->new( 'mysql://crm:r0v@127.0.0.1/yancy' ) },
    read_schema => 1,
};

  1. Заапускаем mojo приложение, например через morbo app.pl

Появляется роут http://127.0.0.1:3000/yancy где поднимается простейший интерфейс администрирования БД

На роуте http://127.0.0.1:3000/yancy/api появится сгенерированная схема API, которую можно использовать в Swagger

const ui = SwaggerUIBundle({
        urls: [
          {name: "Yancy API",                  url: "/yancy/api"},
        ],

FAQ #

Как вместо названия таблицы отображать что-то более человекопонятное? #

Прописать в конфиге параметр schema.<table_name>.title

Пример:

schema:
  flights:
  cities_iata:
    title: IATA коды городов

Как отображать все поля базы в админке? #

Cейчас отображаются по умолчанию только поля 'id', 'name', 'username', 'title', or 'slug'.

Задать что ещё отображать в админке и в каком формате можно при помощи x-list-columns

Примеры:

schema:
  flights:
    x-list-columns:
    - flight_date
    - flight_num
cities_iata:
    title: IATA коды городов
    example:
      name: Санкт-Петербург
      iata: LED
    x-list-columns:
      - title: Город
        template: '{name} ({iata})'

Raspberry PI #

Питание #

Рекомендуется использовать зарядку на 2.5А и AWG20 USB cable

Запись образа на SD-карточку (в примере это том /dev/sdc) #

dd bs=4M if=2017-04-10-raspbian-jessie.img of=/dev/sdX

C progress bar:

pv -tpreb | dd bs=4M if=2017-04-10-raspbian-jessie.img of=/dev/sdX

Через pipe

unzip -p 2017-01-11-raspbian-jessie.zip | pv -tpreb | sudo dd of=/dev/null bs=64M

dcfldd:

sudo dcfldd if=Armbian_5.25_Lamobo-r1_Ubuntu_xenial_default_3.4.113.img of=/dev/sdc bs=64M

GUI:

https://etcher.io/

Что делать если образ не загружается правильно #

Прежде чем пробовать другой образ

Запуск Docker на RaspberryPi #

Любой образ запустить не получится,только для архитектуры ARM. Базовые образы можно найти на:

https://hub.docker.com/r/resin (единственный образ с работающей из коробки wiringpi)

https://hub.docker.com/r/armhf/ (old)

https://hub.docker.com/u/arm32v6/

https://github.com/alexellis/docker-arm

Запуск docker-compose на Raspberry PI #

sudo apt-get -y install python-pip
sudo pip install docker-compose

Включить ssh из коробки #

По умолчанию ssh на Raspberry Pi выключен

В разделе boot сделать sudo touch ssh

Автоподключение к нужной wifi точке #

sudo nano /etc/wpa_supplicant/wpa_supplicant.conf

country=GB
ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev
update_config=1


network={
    ssid="MYSSID"
    #psk="passphrase"
    psk=59e0d07fa4c7741797a4e394f38a5c321e3bed51d54ad5fcbd3f84bc7415d73d
}

Управление пинами через shell #

Как создать свой собственный дистрибутив на основе Raspbian. #

Можно например через qemu. Примерная пошаговая инструкция

Автоматическое подключение к openvpn серверу #

Чтобы vpn подключался автоматически нужно ovpn файл положить в /etc/openvpn

Какие существуют одноплатные компьютеры на Linux #

Raspberry Pi, Banana Pi, Orange Pi, BeagleBone и т.д.

Конфиг OpenWRT #

config wifi-device 'radio0'
	option type 'mac80211'
	option channel '11'
	option hwmode '11g'
	option path 'platform/soc/3f300000.mmc/mmc_host/mmc1/mmc1:0001/mmc1:0001:1'
	option htmode 'HT20'

config wifi-iface 'default_radio0'
	option device 'radio0'
	option network 'lan'
	option mode 'ap'
	option ssid 'OpenWrt'
	option encryption 'none'

Raspbian #

Пошаговая инструкция как сделать свой кастомный образ для Raspberry PI из дистрибутива Raspbian

Let’s learn how to modify Raspbian image.

We will make 5 things

  1. Mount/unmount image filesystem
  2. Install additional packets
  3. Enable ssh by default
  4. Setup WiFi passwords
  5. Change default password

1. Mount/unmount image filesystem #

Fistly you need to know what is the start block of target filesystem and what is the block size.

So offset will be = <block_size>*<start_lba>

pavel@pavel-desktop-x79:/media/pavel/X79-NAS/torrent$ fdisk -l rpi_fablab.img
Диск rpi_fablab.img: 1,7 GiB, 1854590976 байтов, 3622248 секторов
Единицы измерения: секторов из 1 * 512 = 512 байтов
Размер сектора (логический/физический): 512 байт / 512 байт
I/O size (minimum/optimal): 512 bytes / 512 bytes
Тип метки диска: dos
Идентификатор диска: 0x11eccc69

Устр-во         Загрузочный Start Конец Секторы  Size Id Тип
rpi_fablab.img1              8192   93813   85622 41,8M  c W95 FAT32 (LBA)
rpi_fablab.img2             94208 3622247 3528040  1,7G 83 Linux

In our example offset is 48234496

So we can mount filesystem following way

sudo mkdir -p /mnt/rpi_fablab
sudo mount -o loop,offset=48234496 rpi_fablab.img /mnt/rpi_fablab

2. Install additional packets #

More info

Most used packets which are not included in distro:

3. Enable SSH by default #

SSH was disabled by default in Raspbian versions released after November 2016

If you want to enable SSH, all you need to do is to put a file called ssh in the /boot/ directory (sudo touch ssh). The contents of the file don’t matter: it can contain any text you like, or even nothing at all. When the Pi boots, it looks for this file; if it finds it, it enables SSH and then deletes the file. Source

4. Setup WiFi passwords #

You can put all known SSIDs and its passwords on /mnt/rpi_fablab/etc/wpa_supplicant/wpa_supplicant.conf file.

country=RU
ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev
update_config=1

network={
    ssid="MakerHouse"
    psk="fab12shenzhen"
}

network={
    ssid="MYFABLAB"
    psk="fab17chile"
}

5. Change default password #

Fastest way is to execute passwd on step 2.

More info

Other ways of customization #

Also you can build fully customized image using pi-gen script https://github.com/RPi-Distro/pi-gen

And you can even build OS image using app of my friend Denis https://cusdeb.com/

Redmine #

Running #

Best way is to run with Docker and docker-compose using official image

docker-compose up

But for now issue with official image still haven’t resolved, so I used bitnami image.

docker-compose.yml:

version: '2'
services:
  mariadb:
    image: 'bitnami/mariadb:latest'
    environment:
      - ALLOW_EMPTY_PASSWORD=yes
    volumes:
      - '${PWD}/mariadb_data:/bitnami/mariadb'
  redmine:
    image: 'bitnami/redmine:latest'
    ports:
      - '80:3000'
    volumes:
      - '${PWD}/redmine_data:/bitnami/redmine'
    depends_on:
      - mariadb
volumes:
  mariadb_data:
    driver: local
  redmine_data:
    driver: local

Backup database #

Below is the script which makes backup of redmine database into directory where it runs


# run it like ./backup-redmine.sh /home/redmine.fablab61.ru

parse_config_yml() {
	cd $1/config
	echo "Extracting database data from $1/config/database.yml"
	USER=$(grep -R "username:" database.yml | grep -o -E "\b(\w+)$")
	PASSWORD=$(grep -R "password:" database.yml | grep -o -E '"\b(\w+)"$' | sed -e 's/^"//'  -e 's/"$//')
	DB=$(grep -R "database:" database.yml | grep -o -E "\b(\w+)$")
	HOST=$(grep -R "host:" database.yml | grep -o -E "\b(\w+)$")
	echo "USER $USER PASS $PASSWORD DB $DB HOST $HOST"
}


PATH_TO_BACKUP=$(pwd)


if [ $# -eq 0 ]
  then
    echo "No arguments supplied. Plese provide abs path to redmine root directory"
  else
    parse_config_yml $1
    echo "Start making dump"
    mysqldump -u $USER -p$PASSWORD $DB > $PATH_TO_BACKUP/redmine-master_$(date +%Y%m%d_%H%M%S).data.sql
fi

Then download it from local server using scp (ssh key must be added):

scp root@fablab61.ru:/root/backups/redmine-master_20170403_231118.data.sql data.sql

It’s better to download database backup once into redmine database shared docker volume (mariadb_data folder in our case)

Then connect to running container:

docker exec -t -i redmine_mariadb_1 /bin/bash

Then import database data:

mysql -u <username> -p<PlainPassword> <databasename> < <filename.sql>

E.g.

mysql bitnami_redmine < data.sql

Then copy all your redmine data (conf, files, plugins, public/plugin_assets and public/themes folders):

mkdir old_redmine_data
scp -r root@fablab61.ru:/home/redmine.fablab61.ru/plugins .
scp -r root@fablab61.ru:/home/redmine.fablab61.ru/files .
scp -r root@fablab61.ru:/home/redmine.fablab61.ru/public/plugin_assets public/plugin_assets
scp -r root@fablab61.ru:/home/redmine.fablab61.ru/public/themes public/themes

In our case there was two plugins: redmine_contacts and redmine_helpdesk

Troubleshoting #

tail -f /opt/bitnami/redmine/logs/production.log

Possible errors #

 [Client 1-4] Cannot checkout session because a spawning error occurred. The identifier of the error is 12747994. Please see earlier logs for details about the error

Useful plugins #

Планировщики #

Данный раздел посвящен выполнению задач по расписанию

at #

ubuntu

# at -f test.sh now + 1 minute
Can't open /var/run/atd.pid to signal atd. No atd running?

alpine

Добавлять задания at можно только на том контейнере(ос) где запущен atd !

# at -m -f v.pl now + 1 minute
warning: commands will be executed using /bin/sh
Cannot open lockfile /var/spool/atd/.SEQ: No such file or directory

Selenium / Selenoid #

curl -X POST 'http://selenoid:4444/wd/hub/session' -d '{ "desiredCapabilities":{ "browserName":"firefox", "enableVNC":true } }'

Mysql #

stackoverflow my favorites

Рекомендации по проектированию БД #

Cоветы по проектированию таблиц и нормализации:

http://hitechnotes.blogspot.com/2014/05/blog-post.html?q=mysql

http://b62.tripod.com/doc/dbbase.htm

Помнить что есть три уровня нормализации!

Не рекомендуется обзывать колонки также как и ключевые слова

https://dev.mysql.com/doc/refman/8.0/en/keywords.html

AUTO_INCREMENT поле в таблице может быть всего одно и оно обязательно должно быть PRIMARY_KEY

there can be only one auto column and it must be defined as a key

Поэтому создать такую таблицу не получится:

CREATE TABLE checks (
  id INT NOT NULL AUTO_INCREMENT                    COMMENT 'ID проверки',
  epoch int(11) NOT NULL PRIMARY KEY                COMMENT 'current unix epoch timestamp',
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci, COMMENT='Все cron проверки';

Различия MariaDB и MySQL #

Because MariaDB uses the C escape syntax in strings (for example, “\n” to represent the newline character), you must double any “" that you use in your REGEXP strings.

Two backslash characters, (one for the MariaDB parser, one for the regex library), are required to properly escape a character

Настройка #

Посмотреть compiled defaults:

mysqld --verbose --help

Список всех переменных смотреть тут же или в https://dev.mysql.com/doc/refman/5.7/en/server-system-variables.html

Получить лог баз #

с рестартом

[mysqld]
general_log = on
general_log_file=/usr/log/general.log

без рестарта

SET global log_output = 'FILE';
SET global general_log_file='/Applications/MAMP/logs/mysql_general.log';
SET global general_log = 1;

Как убрать Warning: Using a password on the command line interface can be insecure ? #

Вариант 1:

export MYSQL_PWD=${PASSWORD}; mysql

Вариант 2:

mysql_config_editor

Триггеры #

Если вас не устраивает polling и вам нужны хуки - триггеры отличный способ

Так например если вам нужно выполнить внешний скрипты при обновлении какой-либо таблицы - смотрите на https://github.com/mysqludf/lib_mysqludf_sys

Весь список udf

https://github.com/mysqludf

Минус триггеров - не удовлетворяют критериям транзакционности ACID

Частые запросы #

Кластеризация значений таблички #

select sum(case when table_comment <> '' then 1 else 0 end) / count(*)
from INFORMATION_SCHEMA.TABLES

Показать все foreign keys выбранной базы данных #

select
    concat(table_name, '.', column_name) as 'foreign key',  
    concat(referenced_table_name, '.', referenced_column_name) as 'references'
from
    information_schema.key_column_usage
where
    referenced_table_name is not null;

Показать все таблички, в которых есть определённое поле. #

SELECT DISTINCT TABLE_NAME
    FROM INFORMATION_SCHEMA.COLUMNS
    WHERE COLUMN_NAME IN ('lev2','ColumnB')
        AND TABLE_SCHEMA='220_volt';

Показать взаимосвязанные виртуальные таблички (VIEWS) #

Если искомый VIEW - catalog_product, то

SHOW CREATE TABLE catalog_product;
SHOW CREATE VIEW catalog_product

Показать комментарии без использования information_schema #

SHOW FULL COLUMNS FROM <tablename>

Метрики качества sql базы #

Все комментарии к таблицам - SELECT table_comment FROM INFORMATION_SCHEMA.TABLES; Все непустые комментарии к таблицам - SELECT table_comment FROM INFORMATION_SCHEMA.TABLES WHERE table_comment <> ''; Процент откомментированных таблиц - TODO

Примеры интересных запросов в LEFT JOIN и RIGHT JOIN #

SELECT DISTINCT
	TR.id,
	R.title,
    COUNT(N.node_id) PartsCount
FROM Ru_T3_Parts AS parts
	INNER JOIN Ru_T3_C AS C ON (parts.code=C.code)
	INNER JOIN Ru_T3_A AS A ON (A.r_id=C.r_id AND A.set_b1<=1)
	INNER JOIN Ru_T3_Ref1 AS TR ON (A.r_id=TR.r_id)
	INNER JOIN Ru_Ref1 AS R ON (TR.id=R.id)
	INNER JOIN Ru_Node AS N ON (N.node_id=A.node_id)
	LEFT JOIN Ru_T3_Status AS S_major ON (C.code=S_major.code AND S_major.region='61')
	LEFT JOIN Ru_T3_Status AS S_extra ON (C.code=S_extra.code AND S_extra.region='0')
WHERE
	N.lev2 = '654'
	AND (S_major.status > 0 OR S_extra.status > 0)
HAVING PartsCount > 0
ORDER BY
	R.title

Подсчёт статистики через GROUP BY #

SELECT node_length_a1, count(*) C GROUP BY node_length_a1 ORDER BY C ASC;

HAVING vs WHERE #

HAVING используется с аггрегатными операциями

WHERE before GROUP BY and HAVING after GROUP BY

Что делать если MySQLWorkbench показавает поле как blob ? #

https://stackoverflow.com/questions/13634369/mysql-workbench-shows-results-as-blob

Тестирование #

Веб-моки #

https://httpbin.org/

http://slowwly.robertomurray.co.uk/

https://httpstat.us/

VirtualBox #

Чтоб использовать установленную Windows через VirtualBox с Linux хоста нужно сделать rawdisk :

VBoxManage internalcommands createrawvmdk -filename /home/$USER/sdb.vmdk -rawdisk /dev/sda2

Подробности: http://hitechnotes.blogspot.com/2012/07/blog-post.html?q=virtualbox

Wordpress #

Переезд на другой домен #

wp option update home 'http://newdomain.tech'
wp option update siteurl 'http://newdomain.tech'.

Если в вашем блоге включем режим Multisite, то нужно изменить в БД Wordpress в таблицах wp_site и wp_blogs соответствующие ссылки на сайт.

XSLT #

Вывести значение из SQL SELECT

<xmp><xsl:value-of select="@use_proxy_default" /></xmp>