forked from keenerd/pacmatic
/
pacmatic
executable file
·252 lines (225 loc) · 7.21 KB
/
pacmatic
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
#! /bin/bash
# configs
# varname=${varname:-default}
[ -z "$warn_time" ] && warn_time="86400" # seconds
[ -z "$rss_feed" ] && rss_feed="http://www.archlinux.org/feeds/news/"
[ -z "$mail_list" ] && mail_list="http://mailman.archlinux.org/pipermail/arch-general/$(LANG=C printf '%(%Y-%B)T\n' -1).txt"
[ -z "$log_file" ] && log_file="/var/log/arch-news.log"
[ -z "$pacman_log" ] && pacman_log="/var/log/pacman.log"
[ -z "$pacdiff_program" ] && pacdiff_program="pacdiff"
[ -z "$pacman_program" ] && pacman_program="pacman"
[ -z "$config" ] && config="$HOME/.config/pacmatic" # not really a config file ;-)
# log file has one line per entry, with a unix time stamp and escaped news blurb
# keep track of the last mail stamp in $config
# Issues:
# Lots of dirty hacks for processing the RSS subset of XML.
# pacdiff integration is pretty crude.
# Switch to a real config file if it gets one more option.
# Todo:
# More unixy env vars.
# Merge serial seds.
# Backup db.
# Conf file for vars.
# sledgehammer says to watch arch-dev-public and arch-commits
# (sledgehammer also reads no MLs)
mail_summary() # None : None, set $mail_counts and save new stamp
{
stamp="."
if [ -f "$config" ]; then
stamp=$(cat "$config")
fi
raw=$(curl -s "$mail_list" | sed -n "/$stamp/,\$p")
if [ -z "$raw" ]; then
# inefficient, but should only happen once a month
raw=$(curl -s "$mail_list")
fi
new_stamp=$(grep '^Date' <<< "$raw" | tail -n 1)
mail_counts=$(grep -oF "$(expac -Q ' %n-')" <<< "$raw" | sort | uniq -c | sort -nr | awk '{sub(/-$/,"",$2); if(NR!=1) printf ", "; printf "%s(%s)",$2,$1}')
mkdir -p $(dirname "$config")
echo "$new_stamp" > "$config"
}
clean_rss() # none : xml
{
# make xml less unfriendly to grep
# escape \n | remove literal \n | opening tags get a line
curl --connect-timeout 10 -s -o - "$rss_feed" | \
sed "s/^/\\\\n/g" | tr -s "\r\n" " " | sed -r "s/<[^\/]/\n&/g"
}
tag_chop() # xml string : string
{
# this only works for the innermost tags
local data=$1
local tag=$2
#sed "s/<[\/]\?$tag>//g" sed "s|</?$tag>||g"
echo "$data" | grep -o "<$tag>.*</$tag>" | sed "s/<$tag>//g" | sed "s/<\/$tag>//g"
}
log_time() # datetime : seconds
{
# turns a timestamp from pacman.log into unix time
local stamp=`echo "$1 $2" | grep -o -E "[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}"`
date -d "$stamp" +%s
}
last_sync() # none : datetime
{
# can not tell if last sync failed/aborted
log_time `grep 'synchronizing package lists' "$pacman_log" | tail -n 1`
}
last_upgrade() # none : datetime
{
# can not tell if last update failed/aborted
log_time `grep 'starting full system upgrade' "$pacman_log" | tail -n 1`
}
publication_dates() # xml : seconds
{
# collect xml time stamps and unix time them
tag_chop "$1" "pubDate" | while read line ; do
date -d "$line" +%s
done
}
get_news_log() # none : seconds
{
# returns timestamp of last news seen
if [ -f $log_file ]; then
tail -n 1 $log_file | grep -o "^[0-9]*"
else
echo "0"
fi
}
xml_decode() # string : string
{
echo "$1" | sed 's/\t/ /g' | tr -s ' ' | sed 's/</</g' | sed 's/>/>/g' | sed 's/&/&/g'
}
check_news() # none : news (logfile)
{
last_news_date=`get_news_log`
clean=`clean_rss`
pubdates=`mktemp`
descriptions=`mktemp`
header="The latest and greatest news from the Arch Linux distribution."
publication_dates "$clean" > "$pubdates"
tag_chop "$clean" "description" | grep -v "$header" > "$descriptions"
if [[ ! -s "$log_file" ]]; then
echo "Initializing news archive, expect a flood of news."
echo "This will not happen on subsequent launches."
sleep 5
fi
# paste is much happier with files
paste "$pubdates" "$descriptions" | tac | while read -r line ; do
line2=`xml_decode "$line"`
this_date=`echo -n "$line2" | cut -d ' ' -f 1 | sed 's/ //g'`
if [ $(( $this_date )) -gt $(( $last_news_date )) ]; then
line3=$(cut -d ' ' -f 2- <<< "$line2")
if which html2text >& /dev/null; then
echo "$line3" | html2text -style pretty | sed 's/\\n$//'
else
echo "$line3" | sed -e 's|<br />|\n|g' -e 's|\\n||g' -e 's|<p>|\n|g' -e 's|</p>||g'
fi
echo
echo "$line2" >> $log_file
fi
done
rm "$pubdates"
rm "$descriptions"
}
check_checkspace() # none : return value
{
grep -qs '^[ \t]*CheckSpace' /etc/pacman.conf
}
pacnew_count() # none : int
{
find /etc/ \( -name \*.pacnew -o -name \*.pacorig -o -name \*.pacsave \) 2> /dev/null | wc -l
}
docs() # none : docs
{
echo -e "Usage: `basename $0` -options [packages]"
echo -e "\nPacmatic is a pacman wrapper that takes care of menial but critial tasks."
echo -e "\nThese include"
echo -e "\tChecking the archlinux.org news"
echo -e "\tSummarizing the arch-general mailing list"
echo -e "\tReminding if it has been a while since the last sync"
echo -e "\tReporting pacnew files"
echo -e "\tEditing pacnew files"
echo -e "\nThe following environment variables can be set"
echo -e "\twarn_time=\"$warn_time\" # (seconds)"
echo -e "\trss_feed=\"$rss_feed\""
echo -e "\tlog_file=\"$log_file\""
echo -e "\tpacdiff_program=\"$pacdiff_program\""
echo -e "\tpacman_program=\"$pacman_program\""
echo -e "\tmail_list=\"$mail_list\""
echo -e "\tpacman_log=\"$pacman_log\""
echo -e ""
echo -e "To use Pacmatic's functionality in a script, source with"
echo -e "\t. /usr/bin/pacmatic --as-lib"
echo -e ""
}
if [ $# -eq 0 ]; then
docs
exit
fi
[ $1 == "--as-lib" ] && return
current_time=`date +%s`
sync_time=`last_sync`
upgrade_time=`last_upgrade`
case "$1" in
-Syu|-Su|-Suy|-Syyu|-Syuy|-Suyy|-S|-Sy|-Syy)
# do not like this threading
check_news &
mail_summary
wait
echo "Recent ML chatter: $mail_counts"
if ( ! check_checkspace ); then
echo -e "\nPlease enable CheckSpace in pacman.conf"
fi
;;
esac
case "$1" in
-Syu|-Su|-Suy|-Syyu|-Syuy|-Suyy)
#check_news
;;
-S)
#check_news
if [ $(( $sync_time - $upgrade_time )) -gt $(( $warn_time )) ]; then
echo -e "\nWarning: stale installation, rerun with '-Syu'\n"
fi
;;
-Sy|-Syy)
#check_news
if [ $(( $current_time - $upgrade_time )) -gt $(( $warn_time )) ]; then
echo -e "\nWarning: stale installation, rerun with '-Syu'\n"
fi
;;
esac
old_pc=`pacnew_count`
$pacman_program $*
exit_code=$?
exit_time=`date "+[%F %H:%M]"`
if [ -w "$pacman_log" ]; then
echo "$exit_time Exited with code $exit_code" >> "$pacman_log"
fi
new_pc=`pacnew_count`
add_pc=$(( $new_pc - $old_pc ))
# this section is a little clumsy
if [ "$new_pc" = "0" ]; then
echo "No pacnew files to update."
exit 0
fi
case "$1" in
-Syu|-Su|-S|-Sy)
echo -en "\n$new_pc pacnew files found ($add_pc added). Update files now? (Y/n) "
read char
if [ -z "$char" ]; then
$pacdiff_program
fi
case "$char" in
Y|y)
$pacdiff_program
;;
N|n)
;;
*)
;;
esac
;;
*)
;;
esac