Задать вопрос
  • Как объединить несколько версий текста в одну?

    Lobotomist
    @Lobotomist
    Software Developer
    Для объединения двух версий текста можно использовать утилиту diff3, парсить ее вывод, а для пользователя реализовать интерфейс для просмотра ее вывода и решения конфликтов. Готовых библиотек для представления diff в веб я не знаю, но, вероятно, таковые имеются.

    diff3 mine older yours, где mine and yours - версии для слияния, а older - базовая версия.

    Учитывая, что вы хотите хранить историю версий текста - может быть имеет смысл использовать для этого, собственно, гит репозиторий под капотом - он для того и предназначен. В зависимости от специфики можно как иметь по отдельному репозиторию для каждого текста, так и один общий для всех. И в нем хранить историю версий и через него же мерджить версии. Возможно, получится найти и использовать готовые интерфейсы для работы с git через веб, либо надо будет написать свой. А в базе можно хранить только финальный текст, без истории.
    Ответ написан
    1 комментарий
  • Исчезли БД MongoDB?

    Lobotomist
    @Lobotomist
    Software Developer
    Если сделать как вы описали - авторизация происходит успешно. Вероятно, где-то в процессе настройки, либо авторизации была допущена ошибка - например, пользователь создан не в той базе или что-то еще.

    Листинг моей проверки
    docker volume create testvol
    
    docker run --rm --name test-mongo -v "testvol:/data/db" -d mongo
    docker exec -it test-mongo mongo
    use testDb;
    db.createCollection("testCollection");
    use admin;
    
    db.createRole({
    role: "Admin",
    privileges: [{
    resource: {
    db: "testDb",
    collection: "testCollection"
    },
    actions: ["anyAction", "internal"]
    }],
    roles: []
    });
    
    db.createUser({
    user: "Admin",
    pwd: "testpasswd",
    roles: ["Admin"]
    });
    
    db.adminCommand({"listDatabases":1, "filter": {"name": "testDb"}, "nameOnly": true});
    // { "databases" : [ { "name" : "testDb" } ], "ok" : 1 }
    docker stop test-mongo
    
    docker run --rm -v "testvol:/data/db" --name test-mongo -d mongo --auth
    
    docker exec -it test-mongo mongo
    db.adminCommand({"listDatabases":1, "filter": {"name": "testDb"}, "nameOnly": true});
    //{
    //        "ok" : 0,
    //        "errmsg" : "command listDatabases requires authentication",
    //        "code" : 13,
    //        "codeName" : "Unauthorized"
    //}
    
    use admin;
    db.auth("Admin", "testpasswd");
    // 1
    db.adminCommand({"listDatabases":1, "filter": {"name": "testDb"}, "nameOnly": true});
    // { "databases" : [ { "name" : "testDb" } ], "ok" : 1 }


    При отключенной авторизации все базы данных должны быть вам видны по идее. Возможно, созданный пользователь как-то мешает их видеть в админках, через которые вы проверяете, так что используйте команду `listDatabases` для чистоты эксперимента. Запустите базу с отключенной авторизацией, проверьте, что база есть. Если ее нет - вероятно тут уже проблема не связанная с авторизацией - напишите тут об этом. Найдите, где у вас создан пользователь Admin и удалите его.

    docker run --rm -v "testvol:/data/db" --name test-mongo -d mongo
    docker exec -it test-mongo mongo

    use admin;
    // switched to db admin
    db.getUsers();
    // [{ "_id" : "admin.Admin", ...
    db.dropUser("Admin");
    // true


    После этого можно настроить пользователя заново. Возможно, имеет смысл создать "суперпользователя" - пользователя, под которым вы сможете администрировать базу без необходимости перезапускать сервер с отключенной авторизацией. Ведь пользователю Admin вы выдаете права только на одну коллекцию, а не на инстанс и он, я так понимаю, не сможет ни создать дополнительных бд, ни коллекций, ни пользователей.
    Для этого можно использовать роль root, например.

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

    Отмечу, что насчет разрешений, которые вы выдаете вашему пользователю написано:
    > Do not assign this action unless it is absolutely necessary.

    Стоит ему выдать ровно те разрешения, которые ему необходимы для текущей работы, а остальное делать из-под "суперпользователя".
    Ответ написан
    Комментировать
  • Как взять значение из объекта PHP?

    Lobotomist
    @Lobotomist
    Software Developer
    Лично меня от ответа останавливает обилие кода, который нельзя воспроизвести без вашей БД и входных данных.

    Советую вам вычленить проблемный участок кода и оставить в вопросе только его, причем так, чтобы можно было его запустить и воочию наблюдать смущающий вас результат.
    Ответ написан
    Комментировать
  • Почему Docker Compose не работает?

    Lobotomist
    @Lobotomist
    Software Developer
    Вероятно, вы не установили docker-compose.

    Если же вы это сделали - то напишите команды установки, которые вы выполняли.
    Ответ написан
    1 комментарий
  • Как репозиторий может быть связан с документацией проекта?

    Lobotomist
    @Lobotomist
    Software Developer
    Я это понимаю так:

    Под multiroot воркспейсом подразумевается просто-напросто воркспейс, в котором сгруппировано несколько отдельных проектов, каждый может иметь свои настройки в подпапке .vscode. А вот это:

    This can be very helpful when you are working on several related projects at one time. For example, you might have a repository with a product's documentation which you like to keep current when you update the product source code.


    просто пример, когда это может быть удобно использовать. А именно тут приводится случай, когда у вас есть некий проект с исходным кодом и отдельный проект с документацией к этому коду. Они находятся в разных репозиториях. Но редактировать вы их скорее всего захотите одновременно. И поэтому удобно иметь их сгруппированными в одном воркспейсе. Например, добавили аргумент в функцию - нужно обновить и документацию. Удобно это делать когда все затрагиваемые файлы у вас находятся в одном месте - можно использовать глобальный поиск, например, по всем файлам и внести изменения везде где нужно. О том как эти изменения делать тут речи не идет. Так что этот топик не имеет отношения к автогенерации документации.
    Ответ написан
    3 комментария
  • Как ускорить rsync?

    Lobotomist
    @Lobotomist
    Software Developer
    В процессе выяснения деталей в комментариях к вопросу было найдено решение.

    В данном случае синхронизация выполнялась без использования опции `--times`, которая сохраняет время модификации файла при синхронизации. При этом не была использована опция `--size-only`, благодаря которой файлы с одинаковыми размерами считаются одинаковыми вне зависимости от времени изменения.
    И получается, что даты изменения у всех уже синхронизированных файлов отличаются, и rsync при повторном запуске считает эти файлы потенциально разными и считает их контрольные суммы, чтобы сравнить их по содержимому. На это и уходило время.

    Добавление опции `--size-only` существенно сократило время анализа файлов перед началом передачи.
    Хотя, на мой взгляд лучше вместо этого по умолчанию всегда использовать `--times` (в том числе в составе `-a`), если возможно.

    Кроме того, была использована опция `-v`, которая выводит информацию о синхронизируемых файлах, что тоже могло замедлять процесс, хотя, скорее всего ,не значительно.
    Ответ написан
    Комментировать
  • Как сохранить ssh key на хостах?

    Lobotomist
    @Lobotomist
    Software Developer
    Откровенно говоря, я не понял, что вы вообще делаете. Опишу как нужно это делать на мой взгляд.
    Для авторизации по ключу через ssh у клиента должен быть приватный ключ, а на сервере, к которому он подключается - соответствующий публичный ключ.

    Ansible по умолчанию будет работать из-под вашего пользователя (под которым вы работаете на машине с ansible). То есть вам нужно с помощью команды ssh-copy-id поместить публичный ключ этого пользователя на все сервера, которыми вы собираетесь управлять. (Можно это сделать и руками через редактирование на сервере файла ~/.ssh/authorized_keys).

    Еще можно сделать более удобно, на мой взгляд - чтобы когда с машины ansible вы подключаетесь к другим серверам использовался ваш собственный ключ, а не ключ пользователя ansible. Для этого на своей машине вам нужно включить AgentForwarding для хоста с ansible:

    ~/.ssh/config:
    Host myhost.com
      ForwardAgent yes
    Ответ написан
    3 комментария
  • Как сделать продакшн-билд без сорсов в рамках одного репозитория?

    Lobotomist
    @Lobotomist
    Software Developer
    Сначала отмечу пару моментов:

    1. Не храните в гите никаких производных от кода. То есть минифицированных скриптов, стилей и т.п. Они должны собираться из исходников на этапе билдинга и в них не должно внноситься никаких изменений - все изменения только в исходники.
    2. Вы написали, что заказчик может редактировать css и т.п. Тут нужно понимать, что это не часть вашего приложения и вашего кода. Это уже пользовательские данные и в репозитории проекта им не место. Если у вас есть желание их версионировать - вы можете использовать для них свой git репозиторий.

    > хочется иметь на проде только билд проекта - без исходников.

    Есть много способов это сделать. Как вариант, вы можете иметь на проде репозиторий проекта и при деплое использовать его для билдинга конкретного экземпляра системы. Тогда на самом сервере у вас исходники будут, причем можно будет легко получить любую версию, поскольку это репозиторий, но в экземплярах системы - только то, что необходимо. Либо вы можете на CI сервере билдить проект и уже готовый передавать на сервер.
    Ответ написан
    2 комментария
  • Как настроить поиск файлов VS Code при подключении через SFTP / SSH?

    Lobotomist
    @Lobotomist
    Software Developer
    Конкретно на ваш вопрос я ответа не знаю, но могу предложить вам пойти другим путем и работать с файлами локально, синхронизируя их с удаленной машиной. На мой взгляд, это в целом удобнее.

    В VSCode есть, например, плагин liximomo.sftp. Можно включить отслеживане изменений и автоматическую синхронизацию всей папки проекта с удаленным сервером.
    Ответ написан
  • Почему выскакивает ошибка заголовков при формировании csv файла?

    Lobotomist
    @Lobotomist
    Software Developer
    Приглядитесь к ошибке:
    yii\web\HeadersAlreadySentException:
    Headers already sent in /usr/share/nginx/html/project.eng/modules/admin/controllers/ToursController.php on line 1557.
    in /usr/share/nginx/html/project.eng/vendor/yiisoft/yii2/web/Response.php:366


    О чем она говорит? Вы уже отправили заголовки в своем скрипте (ToursController.php on line 1557). А потом в Response.php(339) yii2 пытается снова их отправить и возникает исключение, так как они уже были отправлены.

    Наиболее адекватное решение проблемы - не формировать ответ пользователю руками, а использовать предназначенный для этого класс Response. Как это делать можно прочитать в гайде. Полагаю, вам наиболее уместно отправлять поток `php://output` с помощью sendStreamAsFile.
    Ответ написан
    Комментировать
  • Утечка памяти phpQuery. Как исправить?

    Lobotomist
    @Lobotomist
    Software Developer
    Насколько я понимаю, это известная проблема данного парсера: https://github.com/pein0119/phpquery/issues/192

    Так что если хочется использовать именно его нужно
    * либо найти утечку в самом парсере (видимо, метод phpQuery::unloadDocuments не все указатели удаляет, где-то они остаются) и исправить;
    * либо время от времени перезапускать скрипт;
    * либо использовать другую библиотеку, например nokogiri, как вам посоветовал Immortal_pony;

    Причина утечки, я предполагаю, в том, что phpQuery::$documents свойство публичное и когда элементы массива удаляются внутри unloadDocuments на эти объекты все еще ссылаются какие-то из ваших переменных. Ради эксперимента вы можете сделать unset всех переменных (не только doc) и потом unloadDocuments - просто чтобы проверить мое предположение.
    Ответ написан
    Комментировать
  • Как запросить свежие изменения с GitHub?

    Lobotomist
    @Lobotomist
    Software Developer
    Для начала вам хорошо бы понимать, что такое рабочая директория, индекс и коммит.

    Теперь по сути вопроса: вариантов выполнить желаемое на самом деле много. Вот один из них:
    `git fetch` - получить текущее состояние веток в удаленном репозитории (у вас это уже было выполненоо в рамках git pull, но могли добавиться новые коммиты с тех пор)
    `git reset --hard origin/branchName` - переносим указатель текущей ветки на тот же коммит, на который указывает нужная удаленная ветка и приводим индекс и рабочую директорию к этому коммиту.

    А вообще, вы уверены, что ваши изменения не нужны? Зачем же вы их делали тогда? Возможно, вам стоит их все-таки закоммитить и потом уже делать pull и если они конфликтуют с другими изменениями - решать эти конфликты.
    Ответ написан
    Комментировать
  • Как автоматически загружать измененные файлы на vps?

    Lobotomist
    @Lobotomist
    Software Developer
    Есть множество вариантов. На мой взгляд в качестве протокола наиболее удобно использовать ssh (sftp).

    Вы не написали, в какой ОС вы работаете, но я просто упомяну, что чтобы не привязываться к IDE можно использовать, например, winscp(Windows) или lsyncd(linux) для live синхронизации кода.

    В phpstorm, насколько я понимаю, наряду с ftp можно выбрать и sftp. Но нужно понимать, что переключении между ветками, когда код изменяется не через сохранение файла, а извне редактора он не будет синхронизирован с сервером. В таком случае для синхронизации всего кода удобно использовать rsync (что на linux, что на windows).

    Насчет пользователя и прав - на мой взгляд, веб-сервер не должен иметь прав на запись к исходному коду. То есть нужно при создании инстанса на сервере создать структуру папок, где веб-сервер имеет права на запись только к runtime директориям. А синхронизируемый код - он должен быть доступен серверу только на чтение.
    Отмечу, что я говорю именно об "девелоперском" инстансе, который нужен исключительно для текущей работы. Для инстансов, которые деплоятся автоматически из git ситуация с правами может быть иной и это отдельный вопрос.

    > Знаю, что можно сделать деплой с помощью гита ...

    Вы все правильно написали - это извращение использовать деплой из гита в процессе работы. Дело даже не в лишних коммитах - от них потом можно избавиться. А в совершенно лишних действиях, даже если их автоматизировать на синхронизацию будет уходить неоправданно много времени. Вместо долей секундны будут секунды. Деплой из гита удобно использовать для переноса уже готовых изменений, а не в процессе работы над ними.

    Если есть вопросы - спрашивайте в комментариях, я дополню ответ.
    Ответ написан
    3 комментария
  • Чем опасен force push?

    Lobotomist
    @Lobotomist
    Software Developer
    BD_ l3ftoverZ! ответил в принципе верно - можно затереть чужие изменения, но это не единственная опасность.

    Проблема еще и в том, что старые версии коммитов кто-то получил. И если при форсед пуше в содержимое коммитов были внесены изменения (например, они были поменяны местами и в итоге "сумма изменений" осталась та же, но порядок изменился) при пулле возникнут конфликты при попытке отребэйзить (смерджить) старые версии коммитов на новые. И тут уже все зависит от опытности и внимательности разработчика, который с этим столкнулся. Если он достаточно опытен - он поймет в чем дело и правильно разрулит ситуацию. А если нет - он начнет решать конфликты, накосячит при их решении, при пуше не проверит что он пушит не только свои коммиты, которые собирался, но и старые версии коммитов отребэйзенные на новые версии и это будет... неприятно.

    История из жизни.

    Вот реальная ситуация, которая произошла у меня на работе. К сожалению, за давностью лет конкретные детали я помню смутно, но в целом все было примерно так. В какой-то момент появилась ошибка. Причем код, в котором она была был очень "говнокод", человек его написавший уже уволился и понять в каком месте этот говнокод написан неправильно, не понимая "логики" автора было очень сложно. С помощью git-bisect я нашел проблемный коммит и стал дальше раскручивать клубок. В итоге выяснилось, что было нарушено по крайней мере три важных правила работы с гитом (описанные во внутренней вики и обязательные к исполнению) и если бы хотя бы одно из них нарушено не было - все было бы ок.
    1. Я сделал пуш в мастер и оперативно осознав, что что-то там не так быстренько поправил и залил форсед пушем исправления. Это было важно сделать именно так. Я решил, что во-первых, маловероятно, что кто-то успел сделать пулл, а во-вторых, даже если он и сделал - когда у него возникнут конфликты он либо сам все поймет, либо обратится ко мне. Первое нарушение. Мне следовало уведомить всех разработчиков об этом и объяснить как нужно правильно действовать.
    2. Естественно, один разработчик успел сделать пулл и отребэйзил на старый мастер ветку этого уволившегося и стал доделывать таск. Когда спустя продолжительное время он стал ребэйзить эту ветку на мастер у него полезли конфликты. Он не понял из-за чего эти конфликты возникли. Но храбро все их решил. Етественно, не правльно, уже хотя-бы потому, что он вообще не должен был их решать. Нарушение второго правила - "решай конфликты только тогда, когда ты понимаешь почему они возникли". Обратись он ко мне - все было бы в порядке.
    3. Когда он стал пушить свои изменения он нарушил третье правило: "Всегда проверяй список коммитов, которые ты пушишь". Он не заметил, что кроме "своих" коммитов, он так же пушит чужие, старые версии коммитов мастера, которые он отребэйзил на новые. Он должен был это заметить и забить тревогу - что такое, откуда эти коммиты, я их не делал. Опять же, обратись он ко мне - я бы на месте бы разобрался в чем дело, и исправил ситуацию.

    Так что не надейтесь на авось (как я в данном случае).


    В целом, получается так - если ты понимаешь, что обе проблемы - 1) перезатирание чужих изменений и 2) наличие у кого-то старых версий коммитов не актуальны - смело делай форсед пуш. Например:
    • Это ветка по задаче, в которой работаешь только ты и согласно workflow никто не должен без твоего ведома брать из нее какие-то коммиты.
    • Ты точно знаешь кто имеет доступ к ветке и уверен, что эти люди с ситуацией справятся корректно. Ты их предупредил и они знают что в таких ситуациях делать.
    Ответ написан
    Комментировать
  • Как отрыть файл из командной строки?

    Lobotomist
    @Lobotomist
    Software Developer
    Так по git status видно, что папки compile и release находятся уровнем выше. Вам нужно либо запускать скрипт из корневой директории, либо указывать пути не относительно корня, а относительно папки запуска. А лучше внутри скрипта переходить в определенную директорию и использовать пути относительно нее.

    Третий вариант на мой взгляд самый адекватный, так как иначе легко случайно запустить скрипт не оттуда откуда надо и получить не тот результат.

    Получить путь к директории, в которой физически расположен скрипт можно, например, так:
    scriptPath="$(readlink -f ${BASH_SOURCE[0]})"
    scriptDirPath="$(dirname $scriptPath)"


    Кроме того, в git add нужно передавать только реально существующие папки/файлы, иначе ваш скрипт отвалится на первой же команде, как он и делает сейчас. В данном случае я не вижу файла/папки resource, так что даже если вы поправите пути - скрипт не сработает из-за отсутствия resource.
    Ответ написан
    Комментировать
  • Почему многие отвечают в комментариях под вопросом, вместо написания отдельного ответа?

    Lobotomist
    @Lobotomist
    Software Developer
    Добавлю еще одну возможную причину. На время написания комментария человек не знает - является ли это решением или нет. А если оказывается, что комментарий решает проблему - автор вопроса доволен, проблема решена. А то, что нужно отметить вопрос как решенный - об этом он (и тот, кто ему отвечал) забывает (вообще не думает). Я часто встречаю такие вопросы, заранее не понятно - решит твой вопрос проблему человека или нет. Например, не работает у кого-то соединение по ssh. И причин может быть много разных. Тебе в голову пришла пара возможных вариантов - ты пишешь их в комментариях, задаешь уточняющие вопросы. А потом оказывается, что какое-то из твоих продположений подошло.

    На мой взгляд, разработчикам тостера нужно как-то стимулировать выбор решения для вопроса, если решение по факту было. Либо удаление вопроса как не актуального. В идеале, должно быть так, чтобы любой вопрос без решения был актуальным и пользователь, который может на него ответить не гадал бы, стоит на него тратить время или нет.

    Например, что-то в этом направлении: реализовать напоминание автору вопроса (например, через неделю) о том, что на его вопрос не выбрано ни одного решения. И ему нужно либо выбрать решение, либо удалить вопрос, либо отметить его актуальным (то есть он проверил, решения на вопрос действительно никто не дал и вопрос для него еще актуален). А за невыполнение этих правил - отмечание вопроса актуальным, в то время как по нему есть решение - какие-то штрафные санкции (когда это замечают члены комьюнити).
    Ответ написан
    Комментировать
  • Как исправить Resource Temprorarily unvailable при ssh подключении к любому адресу?

    Lobotomist
    @Lobotomist
    Software Developer
    Для начала нужно локализовать проблему. Проверь подключение к тому же серверу, через другое устройство (например, смартфон). Используя разные каналы связи (домашний интернет и мобильный).

    upd: cehka проверил и оказалось, что с телефона через мобильный интернет подключается, а через домашний нет. Я порекомендовал обратиться в техподдержку провайдера, так как это его область ответственности получается (учитывая, что роутер выдан провайдером).
    Ответ написан
    Комментировать
  • Как откатиться в старой ветке?

    Lobotomist
    @Lobotomist
    Software Developer
    Коротко

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

    Подробно

    git reset --hard commitref, выполненный в master перенесет его указатель на коммит commitref и это в вашем случае не вариант ни при каких условиях, так как master публичная ветка и перезаписывать историю в ней нельзя.

    Убрать коммиты из мастера вы уже никак не можете. Остается только вариант создать коммит(ы), который откатывает часть изменений. Именно это и делает команда git revert. Если откатить нужно всё, что было влито в мастер при слиянии branch-1 и master можно использовать опцию -m для того, чтобы указать относительно какого коммита нужно откатывать изменения.

    Сначала узнаете, какой номер у предыдущего (перед вливанием branch-1) коммита master. Один из вариантов выполнить команду, где branch-1-mergeTo-master - коммит слияния branch-1 и master.
    git log -3 --graph branch-1-mergeTo-master

    В информации о коммите будет строчка, типа такой:
    *   commit 5788ae1df77ce0911f802530b1208f1709c102d4
    |\  Merge: 04d469b 57ed6bd


    Предположим, что коммит мастера имеет id = 04d469b. Тогда его номер - 1. Делаем реверт. Примерные команды:

    git checkout master
    git checkout -b branch-1-revert
    
    git revert -m 1 branch-1-mergeTo-master
    
    git commit -m "branch-1 reverted from master"
    
    git merge master
    git checkout master
    git merge branch-1
    Ответ написан
    Комментировать
  • Почему не работает sscanf?

    Lobotomist
    @Lobotomist
    Software Developer
    Проходите тест кое-где? ;)
    Дело в том, что все это является строкой и соответствует первому спецификатору %s. Насколько мне известно, эти спецификаторы все жадные и нет опции сделать их не жадными. Для того, чтобы дефис не попадал, можно вместо %s использовать, например %[^\-].
    Ответ написан
    1 комментарий
  • Почему терминал не запускается в нужном месте?

    Lobotomist
    @Lobotomist
    Software Developer
    Я не нашел этого в документации, но насколько я понимаю, при загрузке layout, который не содержит ни одной node - создается "пустое" окно. А поскольку режим разделения по умолчанию - splith, новое окно создается справа от существующего "пустого".

    Вообще, рекомендую ознакомиться с документацией, попробовать примеры оттуда.
    Ответ написан
    Комментировать