1#!/usr/bin/perl 2########################################################################### 3# Makefile for API Sanity Checker 4# Install/remove the tool for GNU/Linux, FreeBSD and Mac OS X 5# 6# Copyright (C) 2009-2010 The Linux Foundation 7# Copyright (C) 2009-2011 Institute for System Programming, RAS 8# Copyright (C) 2011-2013 ROSA Lab 9# 10# Written by Andrey Ponomarenko 11# 12# This program is free software: you can redistribute it and/or modify 13# it under the terms of the GNU General Public License or the GNU Lesser 14# General Public License as published by the Free Software Foundation. 15# 16# This program is distributed in the hope that it will be useful, 17# but WITHOUT ANY WARRANTY; without even the implied warranty of 18# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19# GNU General Public License for more details. 20# 21# You should have received a copy of the GNU General Public License 22# and the GNU Lesser General Public License along with this program. 23# If not, see <http://www.gnu.org/licenses/>. 24########################################################################### 25use Getopt::Long; 26Getopt::Long::Configure ("posix_default", "no_ignore_case"); 27use File::Path qw(mkpath rmtree); 28use File::Spec qw(catfile file_name_is_absolute); 29use File::Copy qw(copy); 30use File::Basename qw(dirname); 31use Cwd qw(abs_path); 32use File::Find; 33use Config; 34use strict; 35 36my $TOOL_SNAME = "api-sanity-checker"; 37my $ARCHIVE_DIR = abs_path(dirname($0)); 38 39my $ABICC = "/usr/local/bin/abi-compliance-checker.pl"; 40my $ABICC_VERSION = "1.98.7"; 41 42my $HELP_MSG = " 43NAME: 44 Makefile for API Sanity Checker 45 46DESCRIPTION: 47 Install $TOOL_SNAME command and private modules. 48 49USAGE: 50 sudo perl $0 -install -prefix /usr 51 sudo perl $0 -update -prefix /usr 52 sudo perl $0 -remove -prefix /usr 53 54OPTIONS: 55 -h|-help 56 Print this help. 57 58 --prefix=PREFIX 59 Install files in PREFIX [/usr/local]. 60 61 -install 62 Command to install the tool. 63 64 -update 65 Command to update existing installation. 66 67 -remove 68 Command to remove the tool. 69 70EXTRA OPTIONS: 71 --destdir=DESTDIR 72 This option is for maintainers to build 73 RPM or DEB packages inside the build root. 74 The environment variable DESTDIR is also 75 supported. 76\n"; 77 78if(not @ARGV) 79{ 80 print $HELP_MSG; 81 exit(0); 82} 83 84my ($PREFIX, $DESTDIR, $Help, $Install, $Update, $Remove); 85 86GetOptions( 87 "h|help!" => \$Help, 88 "prefix=s" => \$PREFIX, 89 "destdir=s" => \$DESTDIR, 90 "install!" => \$Install, 91 "update!" => \$Update, 92 "remove!" => \$Remove 93) or exit(1); 94 95sub scenario() 96{ 97 if($Help) 98 { 99 print $HELP_MSG; 100 exit(0); 101 } 102 if(not $Install and not $Update and not $Remove) 103 { 104 print STDERR "ERROR: command is not selected (-install, -update or -remove)\n"; 105 exit(1); 106 } 107 if(my $Version = `$ABICC -dumpversion`) 108 { 109 if(cmpVersions($Version, $ABICC_VERSION)<0) 110 { 111 print STDERR "ERROR: requires $ABICC_VERSION or newer version of \'$ABICC\'\n"; 112 exit(1); 113 } 114 } 115 else 116 { 117 print STDERR "ERROR: cannot find \'$ABICC\'\n"; 118 exit(1); 119 } 120 if($PREFIX ne "/") { 121 $PREFIX=~s/[\/]+\Z//g; 122 } 123 if(not $PREFIX) 124 { # default prefix 125 if($Config{"osname"}!~/win/i) { 126 $PREFIX = "/usr/local"; 127 } 128 } 129 if(my $Var = $ENV{"DESTDIR"}) 130 { 131 print "Using DESTDIR environment variable\n"; 132 $DESTDIR = $Var; 133 } 134 if($DESTDIR) 135 { 136 if($DESTDIR ne "/") { 137 $DESTDIR=~s/[\/]+\Z//g; 138 } 139 if(not isAbs($DESTDIR)) 140 { 141 print STDERR "ERROR: destdir is not absolute path\n"; 142 exit(1); 143 } 144 if(not -d $DESTDIR) 145 { 146 print STDERR "ERROR: you should create destdir directory first\n"; 147 exit(1); 148 } 149 $PREFIX = $DESTDIR.$PREFIX; 150 if(not -d $PREFIX) 151 { 152 print STDERR "ERROR: you should create installation directory first (destdir + prefix):\n mkdir -p $PREFIX\n"; 153 exit(1); 154 } 155 } 156 else 157 { 158 if(not isAbs($PREFIX)) 159 { 160 print STDERR "ERROR: prefix is not absolute path\n"; 161 exit(1); 162 } 163 if(not -d $PREFIX) 164 { 165 print STDERR "ERROR: you should create prefix directory first\n"; 166 exit(1); 167 } 168 } 169 170 print "INSTALL PREFIX: $PREFIX\n"; 171 172 # paths 173 my $EXE_PATH = catFile($PREFIX, "bin"); 174 my $MODULES_PATH = catFile($PREFIX, "share", $TOOL_SNAME); 175 my $REL_PATH = catFile("..", "share", $TOOL_SNAME); 176 my $TOOL_PATH = catFile($EXE_PATH, $TOOL_SNAME); 177 178 if(not -w $PREFIX) 179 { 180 print STDERR "ERROR: you should be root\n"; 181 exit(1); 182 } 183 if($Remove or $Update) 184 { 185 if(-e $EXE_PATH."/".$TOOL_SNAME) 186 { # remove executable 187 print "-- Removing $TOOL_PATH\n"; 188 unlink($EXE_PATH."/".$TOOL_SNAME); 189 } 190 191 if(-d $MODULES_PATH) 192 { # remove modules 193 print "-- Removing $MODULES_PATH\n"; 194 rmtree($MODULES_PATH); 195 } 196 } 197 if($Install or $Update) 198 { 199 if(-e $EXE_PATH."/".$TOOL_SNAME or -e $MODULES_PATH) 200 { # check installed 201 if(not $Remove) 202 { 203 print STDERR "ERROR: you should remove old version first (`perl $0 -remove --prefix=$PREFIX`)\n"; 204 exit(1); 205 } 206 } 207 208 # configure 209 my $Content = readFile($ARCHIVE_DIR."/".$TOOL_SNAME.".pl"); 210 if($DESTDIR) { # relative path 211 $Content=~s/MODULES_INSTALL_PATH/$REL_PATH/; 212 } 213 else { # absolute path 214 $Content=~s/MODULES_INSTALL_PATH/$MODULES_PATH/; 215 } 216 217 # copy executable 218 print "-- Installing $TOOL_PATH\n"; 219 mkpath($EXE_PATH); 220 writeFile($EXE_PATH."/".$TOOL_SNAME, $Content); 221 chmod(0775, $EXE_PATH."/".$TOOL_SNAME); 222 223 if($Config{"osname"}=~/win/i) { 224 writeFile($EXE_PATH."/".$TOOL_SNAME.".cmd", "\@perl \"$TOOL_PATH\" \%*"); 225 } 226 227 # copy modules 228 if(-d $ARCHIVE_DIR."/modules") 229 { 230 print "-- Installing $MODULES_PATH\n"; 231 mkpath($MODULES_PATH); 232 copyDir($ARCHIVE_DIR."/modules", $MODULES_PATH); 233 } 234 235 # check PATH 236 my $Warn = "WARNING: your PATH variable doesn't include \'$EXE_PATH\'\n"; 237 238 if($Config{"osname"}=~/win/i) 239 { 240 if($ENV{"PATH"}!~/(\A|[:;])\Q$EXE_PATH\E[\/\\]?(\Z|[:;])/i) { 241 print $Warn; 242 } 243 } 244 else 245 { 246 if($ENV{"PATH"}!~/(\A|[:;])\Q$EXE_PATH\E[\/\\]?(\Z|[:;])/) { 247 print $Warn; 248 } 249 } 250 } 251 exit(0); 252} 253 254sub cmpVersions($$) 255{ # compare two versions in dotted-numeric format 256 my ($V1, $V2) = @_; 257 return 0 if($V1 eq $V2); 258 my @V1Parts = split(/\./, $V1); 259 my @V2Parts = split(/\./, $V2); 260 for (my $i = 0; $i <= $#V1Parts && $i <= $#V2Parts; $i++) 261 { 262 return -1 if(int($V1Parts[$i]) < int($V2Parts[$i])); 263 return 1 if(int($V1Parts[$i]) > int($V2Parts[$i])); 264 } 265 return -1 if($#V1Parts < $#V2Parts); 266 return 1 if($#V1Parts > $#V2Parts); 267 return 0; 268} 269 270sub catFile(@) { 271 return File::Spec->catfile(@_); 272} 273 274sub isAbs($) { 275 return File::Spec->file_name_is_absolute($_[0]); 276} 277 278sub copyDir($$) 279{ 280 my ($From, $To) = @_; 281 my %Files; 282 find(\&wanted, $From); 283 sub wanted { 284 $Files{$File::Find::dir."/$_"} = 1 if($_ ne "."); 285 } 286 foreach my $Path (sort keys(%Files)) 287 { 288 my $Inst = $Path; 289 $Inst=~s/\A\Q$ARCHIVE_DIR\E/$To/; 290 if(-d $Path) 291 { # directories 292 mkpath($Inst); 293 } 294 else 295 { # files 296 mkpath(dirname($Inst)); 297 copy($Path, $Inst); 298 } 299 } 300} 301 302sub readFile($) 303{ 304 my $Path = $_[0]; 305 return "" if(not $Path or not -f $Path); 306 open(FILE, $Path) || die ("can't open file \'$Path\': $!\n"); 307 local $/ = undef; 308 my $Content = <FILE>; 309 close(FILE); 310 return $Content; 311} 312 313sub writeFile($$) 314{ 315 my ($Path, $Content) = @_; 316 return if(not $Path); 317 open(FILE, ">".$Path) || die ("can't open file \'$Path\': $!\n"); 318 print FILE $Content; 319 close(FILE); 320} 321 322scenario();