-
-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathmerge-lipo
executable file
·103 lines (91 loc) · 3.11 KB
/
merge-lipo
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
#!/usr/bin/perl -w
# This script applies 'lipo' to directories. For each file present in
# any source directory, it will create a file in the destination directory.
# If all the copies of the file in the source directories are the same,
# the file is copied directly to the destination. If there are different
# files in different directories, but the files are executable,
# lipo is run to merge the files together. Otherwise, an error is
# produced.
# Device files and pipes are not supported, but symlinks are; the script
# will check that all the symlinks point to the same place.
# If a file is present in only one of the source directories, it is
# trivially the same as itself and so it is just copied to the destination.
# If there is only one source directory, the script is just an expensive
# version of 'cp -rp'.
# The destination directory is not emptied by this script.
use File::Find ();
use File::Copy ();
use File::Compare ();
use POSIX ();
if ($#ARGV < 1) {
print "usage: $0 <source-directories ...> <dest-directory>\n";
exit 1;
}
# The source directories.
my @sources = @ARGV[0..$#ARGV-1];
# The destination directory.
my $dest = $ARGV[-1];
# Count of errors.
my $errors = 0;
# A hash of the files that need to be lipoed. Only the keys of the
# hash are significant.
my %needs_lipo = ();
# Print an error message.
sub error {
printf STDERR "%s\n",$_[0];
$errors++;
}
# First, scan the directories; copy any files to the destination that are
# identical in the source directory, print error messages, and make
# a list of the files that need lipo-ing.
foreach my $s (@sources)
{
sub eachfile {
my $destname = $dest . '/' . $File::Find::name;
if (-d) {
(mkdir $destname or error ("$destname: $!")) unless (-d $destname);
} elsif (-l) {
my $link1 = readlink;
defined $link1 or error ("$s/$_: $!");
if (-l $destname) {
my $link2 = readlink $destname;
defined $link2 or error ("$destname: $!");
$link1 eq $link2 or error ("$destname: different symlinks");
} elsif (-e $destname) {
error ("$destname: symlink vs. real file");
} else {
symlink $link1,$destname or error ("$destname: $!");
}
} elsif (! -f) {
error ("$destname: no idea how to handle special file");
} elsif (! -f $destname) {
system ("cp", "-p", $_, $destname) == 0 or $errors++;
} elsif (File::Compare::compare ($_, $destname) != 0) {
$needs_lipo{$File::Find::name} = 1;
}
}
chdir $s;
File::Find::find (\&eachfile, '.');
}
# Run lipo.
foreach my $l (keys %needs_lipo) {
# A list of the files to run lipo on.
my @f = ();
# Work out which source directories actually contain this file and
# fill @f.
foreach my $s (@sources) {
my $sf = $s . '/' . $l;
push @f,($sf) if (-f $sf);
}
die "inconsistent directories" if ($#f == -1);
# There might really only be one copy if the file was present
# in the tree before the script was started.
if ($#f == 0) {
system ("cp", "-p", $f[0], $dest . '/' . $l) == 0
or $errors++;
} else {
system ("lipo", "-create", "-output", $dest . '/' . $l, @f) == 0
or $errors++;
}
}
exit ($errors ? 1 : 0);