การกำหนดเวอร์ชันอัตโนมัติเมื่อเปลี่ยนแปลงไฟล์ (แก้ไข / สร้าง / ลบ)


16

ฉันกำลังมองหาการใช้งาน (บน Linux) ของกลไกที่จะทำการเปลี่ยนแปลงใด ๆ ในไดเรกทอรีโดยอัตโนมัติและโปร่งใส สิ่งนี้มีจุดประสงค์เพื่อเพิ่มเติม (อาจแทนที่หากคุณลักษณะที่ร้องขอทั้งหมดมีให้) กับการกำหนดรุ่นมาตรฐาน (SVN, git, ... )

ผลิตภัณฑ์ใน MS Windows ซึ่งทำเช่นนี้คือAutoVer (เพื่อให้มีความคิดที่ดีขึ้นเกี่ยวกับข้อกำหนด) ฉันชอบที่จะมีอะไรแบบนั้น แต่มุ่ง Linux ในสภาพแวดล้อมที่ไม่ใช่กราฟิก

ฉันเห็นว่ามีความพยายามบางอย่างที่จะมี functionnality นี้บน Linux สิ่งที่ใกล้เคียงที่สุดที่ฉันพบคือการทำซ้ำอัตโนมัติในการโค่นล้มแต่ไม่ชัดเจนที่จะใช้กับสภาพแวดล้อมที่มีอยู่

อาจมีบางสิ่งที่ทำงานด้วยinotifyหรือ

ขอบคุณล่วงหน้าสำหรับพอยน์เตอร์ใด ๆ ! WoJ


เกี่ยวข้อง: flashbake
Dan D.


มีข้อกำหนดพิเศษเกี่ยวกับซอฟต์แวร์ที่คุณใช้หรือไม่ เพราะถ้าคุณเพียงแค่ติดตามการเปลี่ยนแปลงที่คุณทำด้วยตนเอง (โดยการแก้ไขไฟล์) Eclipse มีคุณสมบัตินี้ในตัวจึงเรียกว่า "ประวัติท้องถิ่น"
Stefan Seidel

@StefanSeidel ฉันไม่ใช่ผู้เริ่มหัวข้อ แต่ฉันต้องการโซลูชันที่ไม่มี IDE
Michael Pankov

คำตอบ:


6

1. วิธีการใช้งานทั่วไปโดยใช้ตลาดสด

นี่ไม่ใช่การทดสอบของฉัน แต่ฉันพบว่าการเขียนนี้ใช้ประโยชน์จากbzr(ตลาดสด) & inotifywaitเพื่อตรวจสอบไดเรกทอรีและรุ่นควบคุมไฟล์ในนั้นโดยใช้ตลาดสด

สคริปต์นี้ทำงานเพื่อดูการเปลี่ยนแปลงไดเรกทอรีทั้งหมด:

#!/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. ผู้จัดการ / ฯลฯ

สำหรับกรณีพิเศษในการจัดการระบบของคุณ/etcไดเรกทอรีคุณสามารถใช้แอปetckeeper

etckeeper คือชุดเครื่องมือที่จะให้ / etc ถูกเก็บไว้ในที่เก็บคอมไพล์, Mercurial, darcs หรือ bzr มันเกี่ยวข้องกับ apt (และผู้จัดการแพ็คเกจอื่น ๆ รวมถึง yum และ pacman-g2) เพื่อยอมรับการเปลี่ยนแปลงที่ทำกับ / etc โดยอัตโนมัติในระหว่างการอัพเกรดแพ็คเกจ มันติดตามไฟล์ข้อมูลเมตาที่ระบบควบคุม revison ไม่สนับสนุนตามปกติ แต่เป็นสิ่งสำคัญสำหรับ / etc เช่นการอนุญาตของ / etc / shadow มันค่อนข้างจำเพาะและสามารถกำหนดค่าได้ในขณะที่ยังใช้งานง่ายถ้าคุณเข้าใจพื้นฐานของการทำงานกับการควบคุมการแก้ไข

นี่คือบทแนะนำที่ดีเพื่อให้คุณเริ่มต้นได้

3. การใช้คอมไพล์และอินตรอน

เทคนิคนี้จะทำให้การใช้งานและgit incronสำหรับวิธีนี้คุณต้องทำดังต่อไปนี้:

A.ทำธุรกรรมซื้อคืน

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

B.สร้าง$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.เพิ่มรายการลงใน incrontab

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

4. การใช้ Flashbake

อีกตัวเลือกหนึ่งคือการใช้เครื่องมือเช่นFlashbake Flashbake เป็นระบบควบคุมเวอร์ชันที่ Cory Doctorow (จากชื่อเสียงของ BoingBoing) ใช้ในการเขียนหนังสือของเขา

Flashbake ใช้คอมไพล์ภายใต้ประทุนเพื่อติดตามการเปลี่ยนแปลง แต่อยู่ระหว่างการสำรองข้อมูลอัตโนมัติและใช้ระบบควบคุมเวอร์ชันธรรมดาด้วยตัวเอง

คอรีต้องการให้เวอร์ชั่นพกพาสแน็ปช็อตว่าเขาอยู่ที่ไหนในเวลาที่เกิดการกระทำอัตโนมัติและสิ่งที่เขาคิด ฉันร่างสคริปต์ Python อย่างรวดเร็วเพื่อดึงข้อมูลเชิงบริบทที่เขาต้องการและเริ่มแฮ็คสคริปต์เชลล์เพื่อขับคอมไพล์โดยใช้เอาต์พุตของสคริปต์ Python สำหรับการคอมเม้นต์คอมเม้นท์เมื่องาน cron เรียก shell wrapper

ทรัพยากร


3
inotifywait + "git local" = gitwatch.sh ดูที่นี่: github.com/nevik/gitwatch/blob/master/gitwatch.sh
diyism

4

ทันทีZFSมาถึงใจ มันสามารถสร้างภาพรวม - และมีบางโครงการที่จะสร้างภาพรวมโดยอัตโนมัติ


ฉันอ่านเกี่ยวกับ ZFS แต่ดูเหมือนว่าไม่ใช่โซลูชันที่เสถียรสำหรับระบบไฟล์พื้นฐาน (อย่างน้อยใน Linux)
WoJ

ฉันอยากได้วิธีแก้ปัญหาเพื่อตะลึงกับ FS ที่มีอยู่
Michael Pankov

บางทีนี่อาจ? ext3cow.com
Zac B

3

inotifyฉันคิดว่าคุณกำลังอยู่บนเส้นทางที่ถูกต้องด้วย บทความนี้แสดงรายละเอียดการใช้งานพื้นฐานในกรณีที่คล้ายกับของคุณ ผมขอแนะนำให้ใช้มันไม่ว่าจะโดยตรงหรือรวบรวมสาธารณูปโภคเคอร์เนลระดับเช่นfschange นี่คือสิ่งที่สร้างความยุ่งยาก แต่คุณสามารถผูกการตรวจจับการเปลี่ยนแปลงเป็นgit commitหรือคล้ายกัน

โซลูชันเหล่านั้นทั้งคู่มีปัญหาในการพึ่งพาโซลูชันของบุคคลที่สามที่ค่อนข้างไม่สมบูรณ์ หากคุณไม่รังเกียจที่จะทำให้มือสกปรกNodeJSให้สิ่งอำนวยความสะดวกที่ยอดเยี่ยมและข้ามแพลตฟอร์ม ( fs.watch ) สำหรับวัตถุประสงค์ที่แน่นอนนี้ กวดวิชาพื้นฐานในการดูไฟล์สำหรับการเปลี่ยนแปลงใน NodeJS สามารถพบได้ที่นี่ ในไม่กี่โหลบรรทัดหรือน้อยกว่าคุณสามารถเขียนสิ่งที่เฝ้าดูไดเรกทอรีสำหรับไฟล์แล้ว shells out (ผ่านchild_process ) และเรียกใช้ a git commitหรือคล้ายกัน (หรือแม้กระทั่งเพิ่มดัชนีไฟล์เวอร์ชันด้วยตนเองถ้าคุณชอบ roll-your- วิธีการของตัวเอง)

fs.watchได้รับการสนับสนุนโดยinotifyบน linux แต่สามารถใช้งานได้ง่ายกว่ามาก มีโครงการ NodeJS อื่น ๆ ที่ห่อว่าไฟล์ดูการทำงานในระดับต่าง ๆ ของความสะดวกสบายเช่นนี้หรืออย่างใดอย่างหนึ่ง


inotifyยังคงไม่ได้เป็นวิธีการแก้ปัญหาพร้อมและดีผมอาจจะไปกับงูใหญ่ แต่ขอบคุณ.
Michael Pankov

3

inotify (2) บน Linux จะไม่สามารถดูแผนผังขนาดใหญ่ได้ แต่สามารถรวมระบบไฟล์ (ติดตั้งในตำแหน่งที่แยกต่างหาก) ได้ด้วยการแปลคำขอระบบไฟล์เป็นการเรียก svn หรือ git หรือเปลี่ยนเมตาดาต้า svn / git โดยตรง

นี่เป็นแนวคิดที่น่าสนใจมาก แต่ฉันไม่เคยได้ยินเกี่ยวกับการใช้งานที่มีอยู่


สมมติว่าฉันมีไฟล์เพียงไม่กี่ไฟล์
Michael Pankov

0

สคริปต์ดังกล่าวไม่ยากที่จะเขียน

การควบคุมเวอร์ชันที่ฉันชอบคือคอมไพล์

สคริปต์ต่อไปนี้ควรทำ:

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

อาจมีการตรวจสอบไดเรกทอรีของคุณเป็นระยะ - หรือถ้าตัวแก้ไขของคุณโทรแบบสคริปต์ได้หลังจากที่คุณบันทึก

แต่ถ้าคุณทำแบบนี้อาจจะเป็นการดีที่จะยกเว้นไฟล์ขนาดใหญ่และอาจจะมีบางสิ่งที่ "ไร้ประโยชน์" เช่นบันทึกอัตโนมัติ


ใช่ฉันรู้ว่าโซลูชันที่ใช้ cron นั้นง่ายต่อการนำไปใช้ อย่างไรก็ตามฉันกำลังมองหาบางสิ่งบางอย่างซึ่งจะรุ่นในบันทึกไม่ว่ากลไกการบันทึก นี่คือเหตุผลที่ฉันพูดถึง autoversionninf ใน svn และ inotify ในคำถามของฉัน
WoJ

0

SparkleShare ( http://sparkleshare.org ) มีพื้นฐานมาจาก git และใช้ฟังก์ชั่น Dropbox-Like พร้อมการควบคุมเวอร์ชัน แต่คุณต้องตั้งค่า ssh-server (สามารถเป็น localhost)


สิ่งนี้เงอะงะและต้องมีการตั้งค่ามากมาย นอกจากนี้ฟังก์ชั่น Dropbox ไม่จำเป็น
Michael Pankov


0

นอกจากนี้ยังมีวิธี "คนจน" ในการทำเช่นนี้โดยใช้ rsync และงาน cron เท่านั้น โดยทั่วไปคุณใช้เครื่องมืออำนวยความสะดวกในการสำรองข้อมูลของ rsync และใช้เส้นทางสองเส้นทางแยกกันพร้อมส่วนนำหน้า / ส่วนต่อท้ายเพื่อติดตามไฟล์ของคุณ

ดูเหมือนว่าจะน้อยกว่านี้: / usr / bin / rsync -a -A -X - date +".%Y-%m-%d_%H-%M-%S"แบ็คอัพ --suffix = $ source_path $ backup_path

ผลลัพธ์สุดท้าย: การเปลี่ยนไฟล์ชื่อ test_rsync ในพา ธ ต้นทางหลังจากการประมวลผลครั้งแรกจะส่งผลให้ไฟล์ชื่อ test_rsync.2017-02-09_11-00-01 ถูกสร้างขึ้นในพา ธ สำรอง

มีปัญหามากมายเกี่ยวกับเรื่องนี้ (ใช้งานได้หากคุณมีไฟล์ในปริมาณที่เหมาะสมเท่านั้นและจะล้มเหลวสำหรับการเปลี่ยนแปลงที่เกิดขึ้นระหว่างการทำงานสองครั้งติดต่อกันของ rsync (ในกรณีของฉัน 1 นาที)) แต่อาจเพียงพอสำหรับความต้องการของคุณ

หากเรากำลังพูดถึงที่นี่เกี่ยวกับแซมบ้าแชร์รายการยกเว้นอาจอยู่ในลำดับไม่ได้รับรอบที่ฉันยังกลัว

แจ้งให้เราทราบหากคุณปรับปรุงสิ่งนี้


0

นี่คือสคริปต์ Python3 ที่ใช้ VMS เช่นการกำหนดเวอร์ชันไฟล์อัตโนมัติโดยใช้การประทับเวลาต่อท้ายชื่อไฟล์ต้นฉบับเมื่อบันทึก

ฉันใส่ความเห็นลงในสคริปต์และรันสคริปต์ครึ่งโหลบนเครื่องอูบุนตูของฉันโดยมีเฉพาะไดเรกทอรีที่แตกต่างกันในสคริปต์แต่ละเวอร์ชันที่แตกต่างกันดังนั้นฉันจึงวางเวอร์ชันไดเรกทอรีหลายตัวพร้อมกัน ไม่มีโทษจริงกับประสิทธิภาพของเครื่องจักร

! / usr / bin / env python3

พิมพ์ ("PROJECT FILES VERSIONING STARTED") พิมพ์ ("version_creation.py") # แทนที่รหัสนี้ทั้งหมดลงในสคริปต์ของชื่อนี้ print ("run as .. .. 'python3 version_creation.py' จากบรรทัดคำสั่ง") พิมพ์ ("ctrl ' c 'เพื่อหยุด ") พิมพ์ (" ") พิมพ์ (" เพื่อเรียกใช้โปรแกรมในประเภทพื้นหลังด้านล่างไปยังบรรทัดคำสั่งแล้วปิดหน้าต่าง ") พิมพ์ (" nohup python3 version_creation.py ") พิมพ์ (" .... ถึง หยุดกระบวนการไปที่เมนู / การบริหาร / การตรวจสอบระบบ ... และฆ่า python3 ") พิมพ์ (" ") พิมพ์ (" บันทึกไฟล์ไปยังไดเรกทอรี 'ProjectFiles' เสมอและไฟล์รุ่น ") พิมพ์ (" จะถูกสร้างในไดเรกทอรีนั้นด้วย . ") พิมพ์ (" ") พิมพ์ (" ") พิมพ์ (" ") พิมพ์ (" ")

เวลาการนำเข้าระบบการนำเข้า

--- ตั้งช่วงเวลาเพื่อตรวจสอบไฟล์ใหม่ (เป็นวินาที) ด้านล่าง

- ช่วงเวลานี้ควรเล็กกว่าไฟล์ใหม่ที่ปรากฏขึ้น!

t = 10

--- ตั้งค่าไดเรกทอรีต้นทาง (dr1) และไดเรกทอรีเป้าหมาย (dr2)

dr1 = "/ path / to / source_directory"

dr2 = "/ path / to / target_directory"

ระบบการนำเข้าแบบ glob

dr1 = "/ home / michael / ProjectFiles" #both ต้นฉบับและรุ่นจะถูกบันทึกไว้ในไดเรกทอรีนี้

dr2 = "/ home / michael / ProjectFileVersions"

ในขณะที่ 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)

พิมพ์ ("1 Latest_file_path =", latest_file_path)

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

พิมพ์ ("2 originalname =", ชื่อเดิม)

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

พิมพ์ ("filecreation =", สร้างไฟล์)

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

พิมพ์ ("fivesec_ago =", fivesec_ago)

    timedif = fivesec_ago - filecreation #time between file creation

พิมพ์ ("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)

หุ้น

ข้างล่างนี้ถูกวางไว้ก่อนหน้านี้และใช้งานได้ แต่ฉันชอบสคริปต์ไพ ธ อนด้านบนดีกว่ามาก ...... (ใช้ python ประมาณ 3 ชั่วโมง)

#!/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
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.