1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
#!/usr/bin/python
# Author: Maxim 'Saidai no' Krivchikov
# Version: 0.1
# Date: October 29, 2009
#
# Backup copying script. Copy files specified in list file
# from base directory to backup directory. In list file it's
# possible to use masks
#
from sys import exit, argv
from shutil import copy2, copytree
from relpath import abs2rel, rel2abs
from os import popen, makedirs, walk, listdir, remove
from os.path import exists, isdir, join, dirname, isabs, abspath, getmtime
import re
import fnmatch
import os
# Print help and exit
def help():
print 'Usage: sn-backup.py <list-file> <base directory> <backup directory>'
exit(1)
# Read list
def read_list(filename):
nlist = [ ]
with open(filename, 'r') as f:
for line in f:
t = line.split('\t')
# If we have no mask for this line => mask is *
if len(t) == 1:
nlist.append([t[0].rstrip('\r\n'), '*'])
continue
elif len(t) == 2:
[path, mask] = t
# If we have mask and some other \t'ed characters
# copy just first two parts
# FIXME: now path and mask have to be splitted by _one_ \t
elif len(t) > 2:
[path, mask, c] = t
mask.rstrip('\r\n')
nlist.append([path, mask])
f.closed
return nlist
# <=> mkdir -p
def makedirp(dirpath):
if not isdir(dirpath):
makedirs(dirpath)
# remove whitespaces from string
def remove_whitesp(string):
string = string.strip()
re.sub(r'\s', '', string)
return string
# File name satisfies one of patterns
def locate_pred(filename, patterns):
val = False
for p in patterns:
val = val or fnmatch.fnmatch(filename, p)
return val
# Find in root all files and dirs satisfying patterns
# Slightly modified version of locate from:
# http://www.brunningonline.net/simon/blog/archives/002022.html
def locate(patterns, root):
for path, dirs, files in walk(root):
for filename in [abspath(join(path, filename)) for filename in files if locate_pred(filename, patterns)]:
yield filename
for filename in [abspath(join(path, filename)) for filename in dirs if locate_pred(filename, patterns)]:
yield filename
# Copy src to dst considering modification time of individual files.
# src should be directory.
# Warning: there is os.remove() call here. Use with caution :)
def copy_tree(src, dst):
if (src == dst):
return
names = listdir(src)
for n in names:
src_name = join(src, n)
dst_name = join(dst, n)
if os.path.isdir(src_name):
if not isdir(dst_name):
if exists(dst_name) and getmtime(src_name) > getmtime(dst_name):
try:
remove(dst_name)
copytree(src_name, dst_name)
except Exception as e:
print "Error!"
print e
else:
try:
copytree(src_name, dst_name)
except Exception as e:
print "Error!"
print e
else:
copy_tree(src_name, dst_name)
elif not exists(dst_name) or getmtime(src_name) > getmtime(dst_name):
try:
copy2(src_name, dst_name)
except Exception as e:
print "Error!"
print e
# Update individual item
def update_item(path, mask, back_dir, base_dir):
dst_name = rel2abs(path, back_dir)
src_name = rel2abs(path, base_dir)
if not exists(src_name):
print src_name + ' doesn\'t exists!'
return
if not isdir(src_name):
try:
if exists(dst_name) and getmtime(src_name) > getmtime(dst_name):
return
makedirp(dirname(dst_name))
copy2(src_name, dst_name)
return
except Exception as e:
print "Error!"
print e
mask_list = mask.split(',')
for index, mask in enumerate(mask_list):
mask_list[index] = remove_whitesp(mask)
if '*' in mask_list:
copy_tree(src_name, dst_name)
return
files_to_copy = locate(mask_list, src_name)
for f in files_to_copy:
target = rel2abs(abs2rel(f, base_dir), back_dir)
if exists(target):
if getmtime(f) <= getmtime(target):
continue
if not isdir(f):
try:
if not exists(dirname(target)):
makedirp(dirname(target))
copy2(f, target)
except Exception as e:
print "Error!"
print e
else:
copy_tree(f, target)
def main():
print 'Saidai no\' backup script, v0.1'
if len(argv) < 4:
help()
src_file = argv[1]
base_dir = rel2abs(argv[2])
back_dir = rel2abs(argv[3])
if not exists(src_file):
print 'Error: can\'t read source list file: ' + src_file
exit(1)
if not isdir(base_dir):
print 'Error: can\'t read base directory: ' + base_dir
exit(1)
if not isdir(back_dir):
print 'Error: can\'t read backup directory: ' + back_dir
exit(1)
items = read_list(src_file)
for path, mask in items:
if exists(join(base_dir, path)):
print 'Processing ' + mask + ' in ' + path
update_item(path, mask, back_dir, base_dir)
else:
print 'Error: can\'t read ' + join(base_dir, path)
main()