aboutsummaryrefslogtreecommitdiff
path: root/slacksrc
blob: 4cc6d19d5d684c70555d8862b926d715b8fff639 (plain)
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
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
#!/bin/bash

# slacksrc - wget the slackware source for a Slackware package.
# B. Watson (yalhcru@gmail.com)

# I thought this would be a quicky one-liner (or anyway less than 10
# lines), but it's grown into a monster.

set -e

DEFAULTMIRROR="http://ftp.slackware.com/pub/slackware"
MIRROR="${MIRROR:-$DEFAULTMIRROR}"
TMP="${TMP:-/tmp}"
CACHEDIR="$HOME/.slacksrc"
FILELIST="$CACHEDIR/FILE_LIST"
TMPFILE="$TMP/slacksrc.$RANDOM.$$"
SELF="$( echo $0 | sed 's,.*/,,' )"

# everyone's favorite perl function
die() {
	echo -n "$SELF: " 1>&2
	if [ -n "$@" ]; then
		echo "$@" 1>&2
	else
		echo "internal error, contact author" 1>&2
	fi
	rm -f "$TMPFILE"
	exit 1
}

# /etc/slackware-version sometimes contains extra stuff past the
# actual version number (for Slack 9.0, it says 9.0.0, and I remember
# at least one old version with a name in parentheses). So sed out
# everything but major.minor. This will still be wrong on a -current
# system, but anyone running -current is smart enough to read and
# edit this script.
SLACKVER="$( \
	sed \
		's,slackware \+\([0-9]\+\.[0-9]\+\).*$,\1,i' \
		/etc/slackware-version 2>/dev/null || \
	echo Not-Slackware )"

if [ -z "$1" ] || [ "$1" == "--help" ]; then
	exec perldoc $0

	# This never actually runs.
	cat <<EOF
=pod

=head1 NAME

slacksrc - download source directory of an official Slackware package

=head1 SYNOPSIS

slacksrc [-o] [slack_ver] [series]/package

=head1 DESCRIPTION

Downloads the source directory of an official Slackware package with wget.

By default, the latest version from patches/source/ is downloaded. If
you need the original release version source, use the B<-o> option.

Default Slackware version is determined by looking at
/etc/slackware-version, if the B<slack_ver> argument isn't given.

The slack_ver argument can be any slackware from 3.3 to
the present, including current (although current can't be
autodetected, since /etc/slackware-version never actually
says 'current'). Not all mirrors carry all old Slackware
versions. If you're looking for really old sources, the mirror at
ftp://ftp.heanet.ie/mirrors/ftp.slackware.com/pub/slackware/ goes all
the way back to Slackware 1.0.1, although this script only works on
3.3 and newer (3.3 was the first version with FILELIST.TXT).

The package name is matched against FILE_LIST from the server. If only
one match is found, the source for that package is downloaded and saved
in a subdirectory of the current directory (named after the package). If
multiple matches are found, they are listed, but nothing is downloaded.

If the package name is a full name, like bash-4.2.037-x86_64-1 (possibly
with a .t?z extension), the version/build/arch/extension will be removed.
Likewise if the name is a full pathname (beginning with e.g. /var/log),
the directory name will be removed. For this reason, there is NO guarantee
that the source will match any version number provided.

Searching is done with grep, so the package name can be a regex. The list
entries look like 'a/pkgname/', so you can do:

  a/foo    - all packages in a/ series beginning with 'foo'
  a/foo/   - exact match, foo package in a/ series
  /foo/    - exact match in any series
  foo.*bar - any series, matching the (unanchored!) regex

Because the list contains a trailing slash, you can't use $ to anchor the
end of the match (just match the / instead).

The environment variable MIRROR can be set to the Slackware mirror site
to use. This should be the URL of the top level of the mirror. You can
copy the URLs from http://mirrors.slackware.com/mirrorlist/ (only http:
or ftp: mirrors though, rsync not supported). Default mirror is

The FILE_LIST file is cached at I<~/.slacksrc/FILE_LIST-<slack_ver>>.
There's not a lot of error checking. If things go wrong, check the contents
of the cache file or just rm it and try again.

If you want to mirror all the Slackware source (for all packages), this
is the wrong tool for the job. Use rsync or wget instead. If you're
looking for the source to a 3rd-party package (from slackbuilds.org or
slacky.eu maybe), you're using the wrong tool again.

=head1 AUTHOR AND COPYRIGHT

This is slacksrc v0.1 by B. Watson (yalhcru@gmail.com).
Released under the WTFPL: do WTF you want with this. See
http://www.wtfpl.net/txt/copying/.

=cut
EOF
	exit 0
fi

if [ -z "$HOME" ]; then
	die "HOME not set. Please fix this and try again."
fi

if [ "$1" = "-o" ]; then
	PATCHES=no
	shift
fi
 
if [ "$2" != "" ]; then
	SLACKVER="$1"
	shift
fi

if [ "$SLACKVER" = "Not-Slackware" ]; then
	die "This ain't Slackware, you'll have to tell me the Slack version you want"
fi

FILELIST="$FILELIST-$SLACKVER"

PKG="$1"
TOPDIR=$MIRROR/slackware-$SLACKVER
SRCDIR=$TOPDIR/source

if ! wget -q --spider "$TOPDIR"; then
	die "$TOPDIR not found on server, are you sure $SLACKVER is a valid version?"
fi

# Remove local dir name. Only works with absolute paths (relative
# paths are assumed to be the package series, sorry)
PKG="$( echo "$PKG" | sed 's,^/.*/,,' )"

# Remove .tgz/txz/tar extension
PKG="$( echo "$PKG" | sed 's,\.\(t.z\|tar\)$,,' )"

# Remove version/arch/build. Since we can't know whether the input
# *has* a version-arch-build, we can't use the standard cut|rev stuff
# to remove it. So we use some heuristics that might one day need to
# change (particularly, new arches might need to be added to the list).
PKG="$( echo "$PKG" | sed 's,-[^-]\+-\(x86_64\|i.86\|arm\|s390\|ppc\|ppc64\)-[0-9][^-]*$,,' )"

# The sed|sort below extracts only the first 2 directory name components
# after the source/. Earlier slack versions didn't list directories in
# FILELIST.TXT (only the files in them) or else we could simplify this.
# Basically, we have something like ./source/a/less/SlackBuild, and we
# keep only the a/less/ part (note the trailing slash).
if [ ! -s $FILELIST ]; then
	mkdir -p $CACHEDIR
	wget -O- $TOPDIR/FILELIST.TXT | \
		sed -n 's,.*\./source/\([^/]\+/[^/]\+/\).*$,\1,p' | \
		sort -u > $FILELIST 

#TODO: handle extra/ somehow
#wget -O $FILELIST.tmp $TOPDIR/FILELIST.TXT
fi

rm -f $TMPFILE

# The files in $FILELIST have trailing slashes, sed them out.
grep "$PKG" $FILELIST | sed 's,/$,,' > $TMPFILE

LINES=$( wc -l $TMPFILE | cut -d' ' -f1 )

URL=""
case "$LINES" in
	0) die "Can't find any packages matching '$PKG' in $FILELIST"
		;;
	1) URL="$SRCDIR/$( cat $TMPFILE )/"
		;;
	*) echo "Ambiguous match, '$PKG' matches:"
		echo
		cat $TMPFILE
		echo
		;;
esac

rm -f $TMPFILE
if [ -z "$URL" ]; then
	die "Couldn't determine source URL"
fi

PKGDIR=$( echo "$URL" | sed 's,.*/\([^/]\+\)/,\1,' )

if [ -e "$PKGDIR" ]; then
	die "Directory '$PKGDIR' already exists, move or remove it first"
fi

# 20200706 bkw: see if there's a patches/, use that if found.
PATCHURL="$( echo "$URL" | sed "s,source/[^/]*/\([^/]*\)/,patches/source/\1/," )"

#echo "Original source dir URL: $URL"
#echo "Patch source dir URL: $PATCHURL"

if [ "$PATCHES" = "no" ]; then
	echo "-o option given, not looking in /patches!"
else
	if wget -q --spider "$PATCHURL"; then
		echo "Patch URL exists, using it"
		URL="$PATCHURL"
	else
		echo "Patch URL doesn't exist, using original source"
	fi
fi

echo $URL

# Unfortunately, the Slackware mirrors don't all have the same dir
# structure (/pub/slackware vs. /pub/Linux/slackware, etc). We have
# to count the leading directories so we can tell wget how many dirs
# to strip off. The shell isn't really suited to this, but I don't wanna
# rewrite in a real language.

# In English... the first sed expression removes the
# proto://hostname. The 2nd removes the final directory name
# (e.g. /bash/), and the third replaces the slashes in the remaining
# part, with newlines (ASCII 0x0a). So we get one dir name per line,
# which is exactly what "wc -l" will count for us.
CUTDIRS=$( echo "$URL" | \
           sed -e 's,^[a-z]\+://[^/]\+/,,' \
               -e 's,/[^/]\+/$,,' \
               -e 's,/,\x0a,g' | \
           wc -l )

# wget will retrieve the server-generated index files (index.html??C=D;O=D
# and friends), so reject them with -R. The -l10 might be overkill (it's
# the recursion level limit), but it won't hurt anything.
wget -q -r -l10 -nH -np -R'index.html*' --cut-dirs=$CUTDIRS "$URL"

# The icing on the cake: make the SlackBuild executable.
chmod 0755 $PKGDIR/*SlackBuild 2>/dev/null || true

echo
echo "Files saved to ./$PKGDIR:"
ls -ld $PKGDIR/*