forked from eisop-plume-lib/plume-scripts
-
Notifications
You must be signed in to change notification settings - Fork 0
/
cygwin-runner
executable file
·155 lines (133 loc) · 5.17 KB
/
cygwin-runner
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
: # Use -*- Perl -*- without knowing its path
eval 'exec perl -S -w $0 "$@"'
if 0;
# cygwin-runner -- Run a Windows command as if it were a Unix (Cygwin) command.
# Jeremy Nimmer <[email protected]>
# Time-stamp: <2010-08-13 19:33:46 mernst>
# This script takes a command with arguments and translates those
# arguments from cygwin-style filenames into windows-style filenames.
# Its real advantage is the little bit of intelligence it has as far as
# which things are files and which are not.
# The first argument to cygwin-runner is the directory that the
# target program lives in. The second argument is the name of the
# program to be invoked. This can contain path information, which
# will be stripped and ignored. The rest of the arguments are passed
# on to the target program after filename translation. For instance,
# "cywin-runner /java/winbin /java/cygbin/javac -version" will run
# "/java/winbin/javac -version" in windows filespace.
# Therefore, a useful way to run this program is as follows:
#
# * Create a new cygbin directory for each winbin directory you have
#
# * Add a file called .runner to cygwin, with contents like:
# #!/bin/bash
# [...path-to...]/cygwin-runner /java/winbin $0 $*
# The first line is sh-bang notation to say that we want bash to
# run this. The second line runs the cygwin-runner script, passing
# it the path to the winbin directory, the name of the program the
# user ran ($0), , and the rest of the arguments
#
# * For each name in winbin, symlink that name to .runner in cygbin
# $ cd cygbin
# $ ln -s .runner java
# $ ln -s .runner javac
# ...
# * Put cygbin on your cygwin path, and winbin on your windows path.
# If both paths are derived from the same setting in your setup, then
# put cygbin first. Cygwin will see the cygbin files (symlinks) and
# run them, whereas windows will not try to run the symlinks and will
# fall back to the winbin files.
#
# -------------------------------------------------------------------------
# Autoflush
$| = 1;
# Trim a string
sub trim ( $ ) {
my ($str) = (@_);
$str =~ s/^\s+//;
$str =~ s/\s+$//;
return $str;
}
# Convert a cygwin filename to a (spaceless) windows filename
sub filetowin( $ ) {
my ($unix) = @_;
my $win = trim(`cygpath -ws $unix`);
if ($win ne '') {
# The file actually existed.
my ($unixdir, $unixnotdir);
my ($windir, $winnotdir);
if ($unix =~ m|^(.*/)(.*)$|) {
($unixdir, $unixnotdir) = ($1, $2);
$win =~ m|^(.*\\)(.*)$|;
($windir, $winnotdir) = ($1, $2);
} else {
($unixdir, $unixnotdir) = ("", $unix);
($windir, $winnotdir) = ("", $win);
}
# If the original filename didn't have spaces, use that name
# instead, so we preserve the filename extension.
unless ($unixnotdir =~ m/\s/) {
$win = $windir . $unixnotdir;
}
return $win;
}
# Repeated prune off directories until we have none left
my ($first, $rest) = ($unix, "");
while ($first =~ m|./|) {
$first =~ m|^(.+)/(.*)$| or die;
$first = $1;
$rest = "\\" . $2 . $rest;
if (-e $first) {
return trim(`cygpath -ws $first`) . $rest;
}
}
print STDERR "cygwin-runner{$program}: Warning: Unknown cygwin path $unix\n";
return $unix;
}
# Convert a :-separated list of cygwin filenames to a ;-separated list of (spaceless) windows filenames
sub pathtowin( $ ) {
my ($path) = @_;
my @unixelems = split(/[;:]/, $path);
my @winelems = map { filetowin($_); } @unixelems;
return join(';', @winelems);
}
# Convert some arbitrary command-line argument from cygwin filenames to windows filenames
sub smartconvert {
my ($arg) = @_;
# If it is a filename, we assume it really is a filename
if (-e $arg) {
return filetowin($arg);
}
# If its dirname is a filename, we assume it really is a filename
my $dirname = $arg; $dirname =~ s|^(.*)/.*|$1|;
if (-e $dirname) {
return filetowin($arg);
}
# If it is a :-separated list and conatains at least one filename,
# we assume it is a path
if (($arg =~ /:/) && (scalar(grep { (-e $_) } split(':', $arg)))) {
$arg = pathtowin($arg);
}
# If it has an '=' sign in it, split on that and recurse on each
# half (go heuristics!)
if ($arg =~ /^(.*)=(.*)$/) {
return smartconvert($1) . "=" . smartconvert($2);
}
# We have no idea, so leave it alone
return $arg;
}
# Arguments to cygwin-runner itself
local $bin = shift @ARGV;
local $program = shift @ARGV;
$program =~ s/^.*?(\w+)$/$1/ or die("Could not parse program name");
# Sanity checks of arguments to cygwin-runner itself
die("$program: $bin is not a directory") unless (-d $bin);
die("$program: $bin/$program does not exist or is not executable") unless (-x "$bin/$program");
# Translate the arguments
my @ARGS = map { smartconvert($_); } @ARGV;
my $command = filetowin($bin) . "\\" . $program . " " . join(' ', @ARGS);
my $wincwd = filetowin(trim(`pwd`));
$toexec = "CMD /D /C \"cd $wincwd && $command\"";
#print "[[ $toexec ]]\n";
# Use exec instead of backticks so that error code is propogated
exec($toexec);