Versão automática após alteração de arquivo (modificar / criar / excluir)

15

Estou procurando uma implementação (no Linux) de um mecanismo que atualize de forma automática e transparente qualquer alteração em um diretório (recursivamente). Esta é uma adição (possivelmente substituição se todos os recursos solicitados estiverem disponíveis) para versões padrão (SVN, git, ...)

Um produto no MS Windows que faz isso é AutoVer (para ter uma idéia melhor dos requisitos). Eu adoraria ter algo assim, mas voltado para o Linux em um ambiente não gráfico.

Eu vi que há algumas tentativas de ter essa funcionalidade no Linux, a mais próxima que encontrei é autoversionagem no Subversion , mas não é óbvio implementar em ambientes existentes (servidores onde, por exemplo, arquivos de configuração são locais).

Talvez algo esteja funcionando com inotify ?

Agradeço antecipadamente por qualquer indicação! WoJ

    
por WoJ 15.12.2011 / 10:29

9 respostas

5

1. Método de uso geral usando bazar & inotify

Isso não foi testado por mim, mas eu achei esta escrita up que faz uso de bzr (bazaar) & inotifywait para monitorar um diretório e uma versão controlam os arquivos nele usando o bazar.

Este script faz todo o trabalho de observar o diretório em busca de alterações:

#!/bin/bash

# go to checkout repository folder you want to watch
cd path/to/www/parent/www
# start watching the directory for changes recusively, ignoring .bzr dir
# comment is made out of dir/filename
# no output is shown from this, but wrinting a filename instead of /dev/null 
# would allow logging
inotifywait –exclude \.bzr -r -q -m -e CLOSE_WRITE \
    –format=”bzr commit -m ‘autocommit for %w/%f’” ./ | \
    sh  2>/dev/null 1>&2 &
# disown the pid, so the inotify thread will get free from parent process
# and will not be terminated with it
PID='ps aux | grep inotify | grep CLOSE_WRITE | grep -v grep | awk ‘{print $2}’'
disown $PID

# this is for new files, not modifications, optional
inotifywait –exclude \.bzr -r -q -m -e CREATE \
    –format=”bzr add *; bzr commit -m ‘new file added %w/%f’” ./ | \
    sh  2>/dev/null 1>&2 &
PID='ps aux | grep inotify | grep CREATE | grep -v grep | awk ‘{print $2}’'
disown $PID

exit 0;

2. Gerenciando / etc

Para o caso especial de gerenciar o diretório /etc do seu sistema, você pode usar o aplicativo etckeeper .

etckeeper is a collection of tools to let /etc be stored in a git, mercurial, darcs, or bzr repository. It hooks into apt (and other package managers including yum and pacman-g2) to automatically commit changes made to /etc during package upgrades. It tracks file metadata that revison control systems do not normally support, but that is important for /etc, such as the permissions of /etc/shadow. It's quite modular and configurable, while also being simple to use if you understand the basics of working with revision control.

Aqui está um bom tutorial para você começar a usá-lo.

3. Usando git e incron

Esta técnica faz uso de git e incron . Para este método, você precisa fazer o seguinte:

A. Faça um repo

% mkdir $HOME/git
% cd $HOME/git
% git init

B. Crie um script $HOME/bin/git-autocommit

#!/bin/bash

REP_DIR="$HOME/git"       # repository directory
NOTIFY_DIR="$HOME/srv"    # directory to version

cd $REP_DIR
GIT_WORK_TREE=$NOTIFY_DIR /usr/bin/git add .
GIT_WORK_TREE=$NOTIFY_DIR /usr/bin/git commit -a -m "auto"

C. Adicione uma entrada ao incrontab

% sudo incrontab -e $HOME/srv IN_MODIFY,IN_CREATE,IN_MOVED_FROM,IN_MOVED_TO $HOME/bin/git-autocommit

4. Usando o Flashbake

Outra opção é usar uma ferramenta como o Flashbake . Flashbake é o sistema de controle de versão que Cory Doctorow (da fama BoingBoing) usa para escrever seus livros.

O Flashbake usa o git under the hood para rastrear as mudanças, mas está em algum lugar entre fazer backups automáticos e usar um sistema de controle de versão simples.

Cory wanted the version to carry prompts, snapshots of where he was at the time an automated commit occurred and what he was thinking. I quickly sketched out a Python script to pull the contextual information he wanted and started hacking together a shell script to drive git, using the Python script’s output for the commit comment when a cron job invoked the shell wrapper.

Recursos

por 07.02.2013 / 05:32
4

Imediatamente ZFS vem à mente. Pode criar instantâneos - e há alguns projetos para criar automaticamente instantâneos .

    
por 15.12.2011 / 10:59
3

Acho que você está no caminho certo com inotify . Este artigo detalha seu uso básico em um caso semelhante ao seu. Sugiro usá-lo diretamente ou compilar um utilitário no nível do kernel, como fschange . Isso é um incômodo, mas você pode vincular a detecção de alterações a um git commit ou similar.

Essas soluções têm a questão de confiar em soluções de terceiros um pouco imperfeitas. Se você não se importa em sujar as mãos, o NodeJS oferece um excelente recurso de plataforma cruzada ( fs.watch ) para este propósito exato. Um tutorial básico sobre a observação de arquivos para mudanças no NodeJS pode ser encontrado aqui . Em algumas dezenas de linhas ou menos, você pode escrever algo que observe um diretório de arquivos e, em seguida, descubra (via child_process ) e executa um git commit ou similar (ou até mesmo incrementa manualmente um índice de arquivo de versão, se você gostar da abordagem de teste de rolo).

fs.watch é apoiado por inotify no linux, mas é muito mais intuitivo de usar. Existem outros projetos do NodeJS que envolvem essa funcionalidade de visualização de arquivos em vários níveis de conveniência, como este ou esta .

    
por 05.02.2013 / 15:37
3

inotify (2) no Linux não será capaz de ver uma árvore grande, mas o sistema de arquivos (montado em local separado) provavelmente poderia manipulá-lo, traduzindo as solicitações do sistema de arquivos para chamadas svn ou git, ou alterando o svn / git metadados diretamente.

Esta é uma ideia muito interessante, mas eu não tinha ouvido falar de nenhuma implementação existente.

    
por 05.02.2013 / 16:05
0

Esse roteiro não é difícil de escrever.

Meu controle de versão favorito é o git.

o seguinte script deve ser feito:

#!/bin/sh
git add .
git commit -am "my automatic commit"

ou que periodicamente verifique o seu diretório - ou se o seu editor for chamado por script depois de salvar.

Mas se você fizer assim, pode fazer sentido excluir arquivos grandes e talvez alguns "inúteis", como autosaves.

    
por 16.12.2011 / 10:36
0

SparkleShare ( link ) é baseado no git e implementa uma funcionalidade semelhante ao Dropbox com controle de versão, mas você precisa configurar um servidor ssh (pode ser localhost).

    
por 05.02.2013 / 18:29
0

Eu recomendo que você experimente o NILFS. Consulte o sobre a página e você será capaz de decidir quem é esse o que você está procurando ou não .

HTH

    
por 07.02.2013 / 18:56
0

Há também uma maneira de "homem pobre" de fazer isso usando apenas o rsync e um cron job. Basicamente, você depende do recurso de backup do rsync e usa dois caminhos separados, além de um prefixo / sufixo para acompanhar seus arquivos.

É mais ou menos assim: / usr / bin / rsync -a -A -X --backup --suffix = date +".%Y-%m-%d_%H-%M-%S" $ source_path $ backup_path

Resultado final: Alterar um arquivo chamado test_rsync no caminho de origem após a execução inicial resultará em um arquivo chamado test_rsync.2017-02-09_11-00-01 sendo criado no caminho de backup.

Há um monte de problemas com isso (funciona se você tiver uma quantidade decente de arquivos e falhará por mudanças que ocorram entre duas execuções consecutivas do rsync (1 minuto no meu caso)), mas pode ser o suficiente para suas necessidades.

Se estivermos falando aqui sobre compartilhamentos de samba, uma lista de exclusão pode estar em ordem, ainda não cheguei a isso.

Deixe-me saber se você melhorar isso.

    
por 02.03.2017 / 10:32
0

Aqui está um script Python3 que faz o VMS como a versão automática de arquivos usando um carimbo de data e hora anexado ao nome do arquivo original quando salvo.

Eu coloquei um monte de comentários no script e executei meia dúzia de tais scripts na minha máquina Ubuntu com apenas os diretórios sendo diferentes em cada versão diferente do script para que eu fosse simultaneamente versionando vários diretórios. Nenhuma penalidade real para o desempenho da máquina.

! / usr / bin / env python3

print ("VERSÃO DE ARQUIVOS DO PROJETO COMEÇADA") print ("version_creation.py") # coloque todo este código no script deste nome print ("run as .. 'python3 version_creation.py' da linha de comando") print ("ctrl 'c' para parar") impressão (" ") print ("Para executar o programa em segundo plano abaixo na linha de comando e feche a janela.") print ("nohup python3 version_creation.py") print (".... para parar o processo ir menu / administração / monitor do sistema ... e matar python3") impressão (" ") print ("Sempre salvar arquivos no diretório 'ProjectFiles' e nos arquivos de versão") print ("também será criado nesse diretório".) impressão (" ") impressão (" ") impressão (" ") print ("")

importe shutil importar os tempo de importação

--- definir o intervalo de tempo para verificar novos arquivos (em segundos) abaixo de

- este intervalo deve ser menor que o intervalo que novos arquivos aparecem!

t = 10

--- define o diretório de origem (dr1) e o diretório de destino (dr2)

dr1="/ caminho / para / source_directory"

dr2="/ caminho / para / destino_diretório"

import glob import os

dr1="/ home / michael / ProjectFiles" # ambos os originais e versões serão salvos neste diretório

dr2="/ home / michael / ProjectFileVersions"

enquanto True:

if os.listdir(dr1) == []:

print ("Empty")

    n = 100
else:
    list_of_files = glob.glob(dr1+'/*')   # * means all if need specific format then *.csv
    latest_file_path = max(list_of_files, key=os.path.getctime)

print ("1 Latest_file_path=", latest_file_path)

    originalname = latest_file_path.split('/')[-1]

print ("2 nome original=", nome original)

    filecreation = (os.path.getmtime(latest_file_path))

print ("filecreation=", filecreation)

    now = time.time()
    fivesec_ago = now - 5 # Number of seconds

print ("fivesec_ago=", fivesec_ago)

    timedif = fivesec_ago - filecreation #time between file creation

print ("timedif=", timedif)

    if timedif <= 5: #if file created less than 5 seconds ago

        nameroot = originalname.split(".")[-0]
        print ("3 nameroot= ", nameroot)

        extension = os.path.splitext(originalname)[1][1:]
        print ("4 extension = ", extension)

        curdatetime = time.strftime('%Y%m%d-%H%M%S')
        print ("5 curdatetime = ", curdatetime)

        newassembledname = (nameroot + "_" + curdatetime + "." + extension)
        print ("6 newassembledname = ", newassembledname)



        source = dr1+"/"+originalname
        print ("7 source = ", source)

        target = dr1+"/"+newassembledname
        print ("8 target = ", target)

        shutil.copy(source, target)


    time.sleep(t)

compartilhar

o abaixo foi colocado antes e funciona, mas eu gosto do script python acima muito melhor ...... (tenho usado python por cerca de 3 horas)

#!/usr/bin/env python3

print ("PROJECT FILES VERSIONING STARTED")
print ("projectfileversioning.py")
print ("run as..  'python3 projectfileversioning.py'       from command line")
print ("ctrl 'c'      to stop")
print (" ")
print ("To run program in background type below to command line and then close the window. ")
print ("nohup python3 projectfileversioning.py")
print ("....to stop process go menu/administration/system monitor... and kill python")
print (" ")
print ("Always save files to the 'ProjectFiles' directory and the file ")
print ("   will be redirected to the ProjectFileVersions where")
print ("   time stamped versions will also be created.")
print (" ")
print ("If you like you may then copy/move the versioned and original file from 'ProjectFileVersions' to ")
print ("any other directory you like.")

import shutil
import os
import time

#--- set the time interval to check for new files (in seconds) below 
#-   this interval should be smaller than the interval new files appear!
t = 10

#--- set the source directory (dr1) and target directory (dr2)
#dr1 = "/path/to/source_directory"
#dr2 = "/path/to/target_directory"

import glob
import os

dr1 = "/home/michael/ProjectFiles"
dr2 = "/home/michael/ProjectFileVersions"


while True:

    if os.listdir(dr1) == []:
        n = 100
    else:
        list_of_files = glob.glob(dr1+'/*')   # * means all if need specific format then *.csv
        latest_file_path = max(list_of_files, key=os.path.getctime)
        print ("1 Latest_file_path = ", latest_file_path)

        originalname = latest_file_path.split('/')[-1]
        print ("2 originalname = ", originalname)

        nameroot = originalname.split(".")[-0]
        print ("3 nameroot= ", nameroot)

        extension = os.path.splitext(originalname)[1][1:]
        print ("4 extension = ", extension)

        curdatetime = time.strftime('%Y%m%d-%H%M%S')
        print ("5 curdatetime = ", curdatetime)

        newassembledname = (nameroot + "_" + curdatetime + "." + extension)
        print ("6 newassembledname = ", newassembledname)




        source = dr1+"/"+originalname
        print ("7 source = ", source)

        target = dr2+"/"+originalname
        print ("8 target = ", target)

        shutil.copy(source, target)



        source = dr1+"/"+originalname
        print ("9 source = ", source)

        target = dr2+"/"+newassembledname
        print ("10 target = ", target)

        shutil.move(source, target)
        time.sleep(t)


#share
    
por 12.02.2018 / 02:55