diff options
author | Sergey Poznyakoff <gray@gnu.org> | 2020-01-18 17:18:42 +0200 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org> | 2020-01-19 09:45:55 +0200 |
commit | e3d9037c37a934718c9bc8fb196006fa7c002ac0 (patch) | |
tree | 29a36b983d14afe9ba89e7d4128ce00a8cec09e9 | |
download | file-backup-e3d9037c37a934718c9bc8fb196006fa7c002ac0.tar.gz file-backup-e3d9037c37a934718c9bc8fb196006fa7c002ac0.tar.bz2 |
Initial commit
-rw-r--r-- | .gitignore | 14 | ||||
-rw-r--r-- | MANIFEST.SKIP | 63 | ||||
-rw-r--r-- | Makefile.PL | 34 | ||||
-rw-r--r-- | lib/File/Backup.pm | 117 | ||||
-rw-r--r-- | t/00simple.t | 19 | ||||
-rw-r--r-- | t/01numbered.t | 19 | ||||
-rw-r--r-- | t/02auto.t | 22 | ||||
-rw-r--r-- | t/03backup.t | 32 | ||||
-rw-r--r-- | t/04envar.t | 33 | ||||
-rw-r--r-- | t/TestBackup.pm | 40 |
10 files changed, 393 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..8666cce --- /dev/null +++ b/.gitignore | |||
@@ -0,0 +1,14 @@ | |||
1 | *~ | ||
2 | \#*# | ||
3 | .#* | ||
4 | *.bak | ||
5 | *.tar* | ||
6 | .emacs.* | ||
7 | /tmp/ | ||
8 | /debug.sh | ||
9 | core | ||
10 | /MANIFEST | ||
11 | /MYMETA.* | ||
12 | /Makefile | ||
13 | /blib | ||
14 | /pm_to_blib | ||
diff --git a/MANIFEST.SKIP b/MANIFEST.SKIP new file mode 100644 index 0000000..58696be --- /dev/null +++ b/MANIFEST.SKIP | |||
@@ -0,0 +1,63 @@ | |||
1 | # Avoid version control files. | ||
2 | \bRCS\b | ||
3 | \bCVS\b | ||
4 | \bSCCS\b | ||
5 | ,v$ | ||
6 | \B\.svn\b | ||
7 | \B\.git\b | ||
8 | \B\.gitignore\b | ||
9 | \b_darcs\b | ||
10 | \B\.cvsignore$ | ||
11 | |||
12 | # Avoid VMS specific MakeMaker generated files | ||
13 | \bDescrip.MMS$ | ||
14 | \bDESCRIP.MMS$ | ||
15 | \bdescrip.mms$ | ||
16 | |||
17 | # Avoid Makemaker generated and utility files. | ||
18 | \bMANIFEST\.bak | ||
19 | \bMakefile$ | ||
20 | \bblib/ | ||
21 | \bMakeMaker-\d | ||
22 | \bpm_to_blib\.ts$ | ||
23 | \bpm_to_blib$ | ||
24 | \bblibdirs\.ts$ # 6.18 through 6.25 generated this | ||
25 | |||
26 | # Avoid Module::Build generated and utility files. | ||
27 | \bBuild$ | ||
28 | \b_build/ | ||
29 | \bBuild.bat$ | ||
30 | \bBuild.COM$ | ||
31 | \bBUILD.COM$ | ||
32 | \bbuild.com$ | ||
33 | |||
34 | # Avoid temp and backup files. | ||
35 | ~$ | ||
36 | \.old$ | ||
37 | \#$ | ||
38 | \b\.# | ||
39 | \.bak$ | ||
40 | \.tmp$ | ||
41 | \.# | ||
42 | \.rej$ | ||
43 | |||
44 | # Avoid OS-specific files/dirs | ||
45 | # Mac OSX metadata | ||
46 | \B\.DS_Store | ||
47 | # Mac OSX SMB mount metadata files | ||
48 | \B\._ | ||
49 | |||
50 | # Avoid Devel::Cover and Devel::CoverX::Covered files. | ||
51 | \bcover_db\b | ||
52 | \bcovered\b | ||
53 | |||
54 | # Avoid MYMETA files | ||
55 | ^MYMETA\. | ||
56 | |||
57 | ^debug.sh | ||
58 | ^tmp | ||
59 | ^buildreq | ||
60 | ^\.emacs\.* | ||
61 | |||
62 | \.tar$ | ||
63 | \.tar\.gz$ | ||
diff --git a/Makefile.PL b/Makefile.PL new file mode 100644 index 0000000..84b1f32 --- /dev/null +++ b/Makefile.PL | |||
@@ -0,0 +1,34 @@ | |||
1 | use strict; | ||
2 | use warnings; | ||
3 | use ExtUtils::MakeMaker; | ||
4 | use Module::Metadata; | ||
5 | |||
6 | WriteMakefile( | ||
7 | NAME => 'File::Backup', | ||
8 | VERSION_FROM => 'lib/File/Backup.pm', | ||
9 | ABSTRACT_FROM => 'lib/File/Backup.pm', | ||
10 | LICENSE => 'gpl_3', | ||
11 | AUTHOR => 'Sergey Poznyakoff <gray@gnu.org>', | ||
12 | MIN_PERL_VERSION => 5.006, | ||
13 | PREREQ_PM => { | ||
14 | 'File::Temp' => 0.23 | ||
15 | }, | ||
16 | TEST_REQUIRES => { | ||
17 | 'File::Cmp' => 1.07 | ||
18 | }, | ||
19 | META_MERGE => { | ||
20 | 'meta-spec' => { version => 2 }, | ||
21 | resources => { | ||
22 | repository => { | ||
23 | type => 'git', | ||
24 | url => 'git://git.gnu.org.ua/file-backup.git', | ||
25 | web => 'http://git.gnu.org.ua/cgit/file-backup.git/', | ||
26 | }, | ||
27 | }, | ||
28 | provides => Module::Metadata->provides(version => '1.4', | ||
29 | dir => 'lib') | ||
30 | } | ||
31 | ); | ||
32 | |||
33 | |||
34 | |||
diff --git a/lib/File/Backup.pm b/lib/File/Backup.pm new file mode 100644 index 0000000..8aed3bb --- /dev/null +++ b/lib/File/Backup.pm | |||
@@ -0,0 +1,117 @@ | |||
1 | package File::Backup; | ||
2 | use strict; | ||
3 | use warnings; | ||
4 | use File::Copy; | ||
5 | use File::Temp qw(tempdir); | ||
6 | use File::Basename; | ||
7 | use Exporter; | ||
8 | use re '/aa'; | ||
9 | use Carp; | ||
10 | |||
11 | our $VERSION = '1.00'; | ||
12 | our @ISA = qw(Exporter); | ||
13 | our @EXPORT = qw(BACKUP_NONE | ||
14 | BACKUP_SINGLE | ||
15 | BACKUP_SIMPLE | ||
16 | BACKUP_NUMBERED | ||
17 | BACKUP_AUTO | ||
18 | backup | ||
19 | backup_simple | ||
20 | backup_numbered | ||
21 | backup_auto); | ||
22 | |||
23 | use constant { | ||
24 | BACKUP_NONE => 0, # No backups at all (none,off) | ||
25 | BACKUP_SINGLE => 1, # Always make single backups (never,simple) | ||
26 | BACKUP_SIMPLE => 1, | ||
27 | BACKUP_NUMBERED => 2, # Always make numbered backups (t,numbered) | ||
28 | BACKUP_AUTO => 3 # Make numbered if numbered backups exist, | ||
29 | # simple otherwise (nil,existing) | ||
30 | }; | ||
31 | |||
32 | my %envtrans = ( | ||
33 | none => BACKUP_NONE, | ||
34 | off => BACKUP_NONE, | ||
35 | never => BACKUP_SIMPLE, | ||
36 | simple => BACKUP_SIMPLE, | ||
37 | t => BACKUP_NUMBERED, | ||
38 | numbered => BACKUP_NUMBERED, | ||
39 | nil => BACKUP_AUTO, | ||
40 | existing => BACKUP_AUTO | ||
41 | ); | ||
42 | |||
43 | my %backup_func = ( | ||
44 | BACKUP_NONE() => sub {}, | ||
45 | BACKUP_SIMPLE() => \&backup_simple, | ||
46 | BACKUP_NUMBERED() => \&backup_numbered, | ||
47 | BACKUP_AUTO() => \&backup_auto | ||
48 | ); | ||
49 | |||
50 | sub backup { | ||
51 | my ($file, $type) = @_; | ||
52 | unless (defined($type)) { | ||
53 | my $v = $ENV{VERSION_CONTROL} || BACKUP_AUTO; | ||
54 | if (exists($envtrans{$v})) { | ||
55 | $type = $envtrans{$v}; | ||
56 | } else { | ||
57 | $type = BACKUP_AUTO; | ||
58 | } | ||
59 | } | ||
60 | &{$backup_func{$type}}($file); | ||
61 | } | ||
62 | |||
63 | sub backup_simple { | ||
64 | my ($file_name) = @_; | ||
65 | my $backup_name = $file_name . '~'; | ||
66 | copy($file_name, $backup_name) | ||
67 | or croak "failed to copy $file_name to $backup_name: $!"; | ||
68 | return $backup_name; | ||
69 | } | ||
70 | |||
71 | sub backup_numbered_opt { | ||
72 | my ($file_name, $if_exists) = @_; | ||
73 | |||
74 | my $dir = tempdir(DIR => dirname($file_name), CLEANUP => 1); | ||
75 | my $fh = File::Temp->new(DIR => $dir); | ||
76 | copy($file_name, $fh) or | ||
77 | croak "failed to make a temporary copy of $file_name: $!"; | ||
78 | |||
79 | my $num = (sort { $b <=> $a } | ||
80 | map { | ||
81 | if (/.+\.~(\d+)~$/) { | ||
82 | $1 | ||
83 | } else { | ||
84 | () | ||
85 | } | ||
86 | } glob("$file_name.~*~"))[0]; | ||
87 | |||
88 | if (!defined($num)) { | ||
89 | return backup_simple($file_name) if $if_exists; | ||
90 | $num = '1'; | ||
91 | } | ||
92 | |||
93 | my $backup_name; | ||
94 | while (1) { | ||
95 | $backup_name = "$file_name.~$num~"; | ||
96 | last if symlink($fh->filename, $backup_name); | ||
97 | ++$num; | ||
98 | } | ||
99 | |||
100 | unless (rename($fh->filename, $backup_name)) { | ||
101 | croak "can't rename temporary file to $backup_name: $!"; | ||
102 | } | ||
103 | return $backup_name; | ||
104 | } | ||
105 | |||
106 | sub backup_numbered { | ||
107 | my ($file_name) = @_; | ||
108 | backup_numbered_opt($file_name, 0); | ||
109 | } | ||
110 | |||
111 | sub backup_auto { | ||
112 | my ($file_name) = @_; | ||
113 | backup_numbered_opt($file_name, 1); | ||
114 | } | ||
115 | |||
116 | 1; | ||