Cleaning up dotfiles
This commit is contained in:
371
bin/git-cal
371
bin/git-cal
@@ -1,371 +0,0 @@
|
||||
#!/usr/bin/perl
|
||||
use strict;
|
||||
|
||||
use utf8;
|
||||
use Getopt::Long;
|
||||
use Pod::Usage;
|
||||
use Data::Dumper;
|
||||
|
||||
binmode(STDOUT, ":utf8");
|
||||
#command line options
|
||||
my ( $help, $period, $author, $filepath );
|
||||
|
||||
GetOptions(
|
||||
'help|?' => \$help,
|
||||
'period|p=n' => \$period,
|
||||
'author=s' => \$author,
|
||||
) or pod2usage(2);
|
||||
pod2usage(1) if $help;
|
||||
|
||||
$filepath = shift @ARGV;
|
||||
|
||||
# also tried to use unicode chars instead of colors, the exp did not go well
|
||||
#qw(⬚ ⬜ ▤ ▣ ⬛)
|
||||
#qw(⬚ ▢ ▤ ▣ ⬛)
|
||||
|
||||
my @colors = ( 237, 157, 155, 47, 2 );
|
||||
my @months = qw (Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec);
|
||||
|
||||
process();
|
||||
|
||||
# 53 X 7 grid
|
||||
# consists of 0 - 370 blocks
|
||||
my ( @grid, @timeline, %pos_month, %month_pos, $jan1, $cur_year, $max_epoch, $min_epoch, $max_commits, $q1, $q2, $q3 );
|
||||
my ( $first_block, $last_block, $start_block, $end_block, $row_start, $row_end );
|
||||
my ( $total_commits, $max_streak, $cur_streak, $max_streak_weekdays, $cur_streak_weekdays );
|
||||
my ( $cur_start, $max_start, $max_end, $cur_weekdays_start, $max_weekdays_start, $max_weekdays_end );
|
||||
#loads of global variables
|
||||
|
||||
sub process {
|
||||
#try to exit gracefully when the terminal doesn't support enough colors
|
||||
no warnings; #dont warn if tput command fails
|
||||
my $colors_supported = qx/tput colors/;
|
||||
if ($colors_supported && $colors_supported < 256) {
|
||||
chomp $colors_supported;
|
||||
print "fatal: 'tput colors' returned < 256 (" . $colors_supported . ") , cannot plot the calendar as the terminal doesn't support enough colors\n"; #will try to hack around this soon
|
||||
exit(1);
|
||||
}
|
||||
init_cal_stuff();
|
||||
my $extra_args = "";
|
||||
$extra_args = " --author=" . $author if $author;
|
||||
if ($filepath) {
|
||||
if ( -e $filepath ) {
|
||||
$extra_args .= " -- " . $filepath;
|
||||
}
|
||||
else {
|
||||
print "fatal: $filepath do not exists\n";
|
||||
exit(2);
|
||||
}
|
||||
}
|
||||
my $git_command = "git log --pretty=format:\"%at\" --since=\"13 months\"" . $extra_args; #commits might not be in strict time order, check some past too
|
||||
my $epochs = qx/$git_command/;
|
||||
if ($?) {
|
||||
print "fatal: git-cal failed to get the git log\n";
|
||||
exit(2);
|
||||
}
|
||||
my @epochs = split /\n/, $epochs;
|
||||
if (! @epochs) {
|
||||
print "git-cal: got empty log, nothing to do\n";
|
||||
exit(1);
|
||||
}
|
||||
my $status;
|
||||
foreach (@epochs) {
|
||||
$status = add_epoch($_);
|
||||
last if !$status;
|
||||
}
|
||||
compute_stats();
|
||||
print_grid();
|
||||
}
|
||||
|
||||
|
||||
sub init_cal_stuff {
|
||||
my ( $wday, $yday, $month, $year ) = ( localtime(time) )[ 6, 7, 4, 5 ];
|
||||
$cur_year = $year;
|
||||
$jan1 = 370 - ( $yday + 6 - $wday );
|
||||
$last_block = $jan1 + $yday + 1;
|
||||
$first_block = $last_block - 365;
|
||||
$max_commits = 0;
|
||||
push @timeline, $jan1;
|
||||
$month_pos{0} = $jan1;
|
||||
my $cur = $jan1;
|
||||
|
||||
foreach ( 0 .. $month - 1 ) {
|
||||
$cur += number_of_days( $_, $year );
|
||||
push @timeline, $cur;
|
||||
$month_pos{ $_ + 1 } = $cur;
|
||||
}
|
||||
$cur = $jan1;
|
||||
for ( my $m = 11; $m > $month; $m-- ) {
|
||||
$cur -= number_of_days( $m, $year - 1 );
|
||||
unshift @timeline, $cur;
|
||||
$month_pos{$m} = $cur;
|
||||
}
|
||||
|
||||
$pos_month{ $month_pos{$_} } = $months[$_] foreach keys %month_pos;
|
||||
|
||||
die "period can only be between -11 to -1 and 1 to 12" if ( defined $period && ( $period < -11 || $period > 12 || $period == 0 ) );
|
||||
$period = 0 if !defined $period;
|
||||
if ( $period == 0 ) {
|
||||
$start_block = $first_block;
|
||||
$end_block = $last_block;
|
||||
}
|
||||
elsif ( $period > 0 ) {
|
||||
$start_block = $month_pos{ $period - 1 };
|
||||
$end_block = $month_pos{ $period % 12 };
|
||||
$end_block = $last_block if $start_block > $end_block;
|
||||
}
|
||||
else {
|
||||
$start_block = $timeline[ 11 + $period ];
|
||||
$start_block = $first_block if $period == -12;
|
||||
$end_block = $last_block;
|
||||
}
|
||||
$row_start = int $start_block / 7;
|
||||
$row_end = int $end_block / 7;
|
||||
$max_epoch = time - 86400 * ( $last_block - $end_block );
|
||||
$min_epoch = time - 86400 * ( $last_block - $start_block );
|
||||
|
||||
( $total_commits, $max_streak, $cur_streak, $max_streak_weekdays, $cur_streak_weekdays ) = (0) x 5;
|
||||
( $cur_start, $max_start, $max_end, $cur_weekdays_start, $max_weekdays_start, $max_weekdays_end ) = (0) x 6;
|
||||
|
||||
}
|
||||
|
||||
|
||||
sub add_epoch {
|
||||
my $epoch = shift;
|
||||
if ( $epoch > $max_epoch || $epoch < $min_epoch ) {
|
||||
return 1;
|
||||
}
|
||||
my ( $month, $year, $wday, $yday ) = ( localtime($epoch) )[ 4, 5, 6, 7 ];
|
||||
my $pos;
|
||||
if ( $year == $cur_year ) {
|
||||
$pos = ( $jan1 + $yday );
|
||||
}
|
||||
else {
|
||||
my $total = ( $year % 4 ) ? 365 : 366;
|
||||
$pos = ( $jan1 - ( $total - $yday ) );
|
||||
}
|
||||
return 0 if $pos < 0; #just in case
|
||||
add_to_grid( $pos, $epoch );
|
||||
return 1;
|
||||
}
|
||||
|
||||
sub add_to_grid {
|
||||
my ( $pos, $epoch ) = @_;
|
||||
my $r = int $pos / 7;
|
||||
my $c = $pos % 7;
|
||||
$grid[$r][$c]->{commits}++;
|
||||
$grid[$r][$c]->{epoch} = $epoch;
|
||||
$max_commits = $grid[$r][$c]->{commits} if $grid[$r][$c]->{commits} > $max_commits;
|
||||
}
|
||||
|
||||
|
||||
sub compute_stats {
|
||||
my %commit_counts;
|
||||
foreach my $r ( $row_start .. $row_end ) {
|
||||
foreach my $c ( 0 .. 6 ) {
|
||||
my $cur_block = ( $r * 7 ) + $c;
|
||||
if ( $cur_block >= $start_block && $cur_block < $end_block ) {
|
||||
my $count = $grid[$r][$c]->{commits} || 0;
|
||||
$total_commits += $count;
|
||||
if ($count) {
|
||||
$commit_counts{$count} = 1;
|
||||
$cur_streak++;
|
||||
$cur_start = $grid[$r][$c]->{epoch} if $cur_start == 0;
|
||||
if ( $cur_streak > $max_streak ) {
|
||||
$max_streak = $cur_streak;
|
||||
$max_start = $cur_start;
|
||||
$max_end = $grid[$r][$c]->{epoch};
|
||||
}
|
||||
|
||||
#count++ if you work on weekends and streak will not be broken otherwise :)
|
||||
$cur_streak_weekdays++;
|
||||
$cur_weekdays_start = $grid[$r][$c]->{epoch} if $cur_weekdays_start == 0;
|
||||
if ( $cur_streak_weekdays > $max_streak_weekdays ) {
|
||||
$max_streak_weekdays = $cur_streak_weekdays;
|
||||
$max_weekdays_start = $cur_weekdays_start;
|
||||
$max_weekdays_end = $grid[$r][$c]->{epoch};
|
||||
}
|
||||
}
|
||||
else {
|
||||
$cur_streak = 0;
|
||||
$cur_start = 0;
|
||||
if ( $c > 0 && $c < 6 ) {
|
||||
$cur_streak_weekdays = 0;
|
||||
$cur_weekdays_start = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#now compute quartiles
|
||||
my @commit_counts = sort { $a <=> $b } ( keys %commit_counts );
|
||||
$q1 = $commit_counts[ int( scalar @commit_counts ) / 4 ];
|
||||
$q2 = $commit_counts[ int( scalar @commit_counts ) / 2 ];
|
||||
$q3 = $commit_counts[ int( 3 * ( scalar @commit_counts ) / 4 ) ];
|
||||
|
||||
#print "commit counts: " . (scalar @commit_counts) . " - " . (join ",",@commit_counts) . "\n\n";
|
||||
#print "quartiles: $q1 $q2 $q3\n";
|
||||
}
|
||||
|
||||
sub print_grid {
|
||||
my $space = 6;
|
||||
print_month_names($space);
|
||||
foreach my $c ( 0 .. 6 ) {
|
||||
printf "\n%" . ( $space - 2 ) . "s", "";
|
||||
if ( $c == 1 ) {
|
||||
print "M ";
|
||||
}
|
||||
elsif ( $c == 3 ) {
|
||||
print "W ";
|
||||
}
|
||||
elsif ( $c == 5 ) {
|
||||
print "F ";
|
||||
}
|
||||
else {
|
||||
print " ";
|
||||
}
|
||||
foreach my $r ( $row_start .. $row_end ) {
|
||||
my $cur_block = ( $r * 7 ) + $c;
|
||||
if ( $cur_block >= $start_block && $cur_block < $end_block ) {
|
||||
my $val = $grid[$r][$c]->{commits} || 0;
|
||||
my $index = 0;
|
||||
|
||||
#$index = ( int( ( $val - 4 ) / $divide ) ) + 1 if $val > 0; #too dumb and bad
|
||||
if ($val) {
|
||||
if ( $val <= $q1 ) {
|
||||
$index = 1;
|
||||
}
|
||||
elsif ( $val <= $q2 ) {
|
||||
$index = 2;
|
||||
}
|
||||
elsif ( $val <= $q3 ) {
|
||||
$index = 3;
|
||||
}
|
||||
else {
|
||||
$index = 4;
|
||||
}
|
||||
}
|
||||
print_block($index);
|
||||
}
|
||||
else {
|
||||
print " ";
|
||||
}
|
||||
}
|
||||
}
|
||||
print "\n\n";
|
||||
printf "%" . ( 2 * ( $row_end - $row_start ) + $space - 10 ) . "s", "Less "; #such that the right borders align
|
||||
print_block($_) foreach ( 0 .. 4 );
|
||||
print " More\n";
|
||||
|
||||
printf "%4d: Total commits\n", $total_commits;
|
||||
print_message( $max_streak_weekdays, $max_weekdays_start, $max_weekdays_end, "Longest streak excluding weekends" );
|
||||
print_message( $max_streak, $max_start, $max_end, "Longest streak including weekends" );
|
||||
print_message( $cur_streak_weekdays, $cur_weekdays_start, time, "Current streak" );
|
||||
}
|
||||
|
||||
|
||||
sub print_block {
|
||||
my $index = shift;
|
||||
$index = 4 if $index > 4;
|
||||
my $c = $colors[$index];
|
||||
#always show on a black background, else it looks different (sometimes really bad ) with different settings.
|
||||
#print "\e[40;38;5;${c}m⬛ \e[0m";
|
||||
print "\e[40;38;5;${c}m\x{25fc} \e[0m";
|
||||
}
|
||||
|
||||
sub print_month_names {
|
||||
#print month labels, printing current month in the right position is tricky
|
||||
my $space = shift;
|
||||
if ( defined $period && $period > 0 ) {
|
||||
printf "%" . $space . "s %3s", "", $months[ $period - 1 ];
|
||||
return;
|
||||
}
|
||||
my $label_printer = 0;
|
||||
my $timeline_iter = 11 + ( $period || -11 );
|
||||
if ( $start_block == $first_block && $timeline[0] != 0 ) {
|
||||
my $first_pos = int $timeline[0] / 7;
|
||||
if ( $first_pos == 0 ) {
|
||||
printf "%" . ( $space - 2 ) . "s", "";
|
||||
print $pos_month{ $timeline[-1] } . " ";
|
||||
print $pos_month{ $timeline[0] } . " ";
|
||||
$timeline_iter++;
|
||||
}
|
||||
elsif ( $first_pos == 1 ) {
|
||||
printf "%" . ( $space - 2 ) . "s", "";
|
||||
print $pos_month{ $timeline[-1] } . " ";
|
||||
}
|
||||
else {
|
||||
printf "%" . $space . "s", "";
|
||||
printf "%-" . ( 2 * $first_pos ) . "s", $pos_month{ $timeline[-1] };
|
||||
}
|
||||
$label_printer = $first_pos;
|
||||
}
|
||||
else {
|
||||
printf "%" . $space . "s", "";
|
||||
$label_printer += ( int $start_block / 7 );
|
||||
}
|
||||
|
||||
while ( $label_printer < $end_block / 7 && $timeline_iter <= $#timeline ) {
|
||||
while ( ( int $timeline[$timeline_iter] / 7 ) != $label_printer ) { print " "; $label_printer++; }
|
||||
print " " . $pos_month{ $timeline[$timeline_iter] } . " ";
|
||||
$label_printer += 3;
|
||||
$timeline_iter++;
|
||||
}
|
||||
}
|
||||
|
||||
sub print_message {
|
||||
my ( $days, $start_epoch, $end_epoch, $message ) = @_;
|
||||
if ($days) {
|
||||
my @range;
|
||||
foreach my $epoch ( $start_epoch, $end_epoch ) {
|
||||
my ( $mday, $mon, $year ) = ( localtime($epoch) )[ 3, 4, 5 ];
|
||||
my $s = sprintf( "%3s %2d %4d", $months[$mon], $mday, ( 1900 + $year ) );
|
||||
push @range, $s;
|
||||
}
|
||||
printf "%4d: Days ( %-25s ) - %-40s\n", $days, ( join " - ", @range ), $message;
|
||||
}
|
||||
else {
|
||||
printf "%4d: Days - %-40s\n", $days, $message;
|
||||
}
|
||||
}
|
||||
|
||||
sub number_of_days {
|
||||
my ( $month, $year ) = @_;
|
||||
return 30 if $month == 3 || $month == 5 || $month == 8 || $month == 10;
|
||||
return 31 if $month != 1;
|
||||
return 28 if $year % 4;
|
||||
return 29;
|
||||
}
|
||||
|
||||
__END__
|
||||
|
||||
=head1 NAME
|
||||
|
||||
git-cal - A simple tool to view commits calendar (similar to github contributions calendar) on command line
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
"git-cal" is a tool to visualize the git commit history in github's contribution calendar style.
|
||||
The calendar shows how frequently the commits are made over the past year or some choosen period
|
||||
|
||||
git-cal
|
||||
git-cal --author=<author> -- <filepath>
|
||||
|
||||
=head2 OPTIONS
|
||||
|
||||
--author view commits of a particular author (passed to git log --author= )
|
||||
--period|p Do not show the entire year, p=1 to 12 shows only one month (1 = Jan .. 12 = Dec), p=-1 to -11 shows last p months and the current month
|
||||
--help|? help me
|
||||
|
||||
=head2 ADDITIONAL OPTIONS
|
||||
|
||||
-- filename to view the logs of a particular file or directory
|
||||
|
||||
=head1 AUTHOR
|
||||
|
||||
Karthik katooru <karthikkatooru@gmail.com>
|
||||
|
||||
=head1 COPYRIGHT AND LICENSE
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it under the MIT License
|
||||
230
bin/peat
230
bin/peat
@@ -1,230 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf8 -*-
|
||||
|
||||
##############################
|
||||
# ____ ___ ____ ______ #
|
||||
# | \ / _] / T| T #
|
||||
# | o )/ [_ Y o || | #
|
||||
# | _/Y _]| |l_j l_j #
|
||||
# | | | [_ | _ | | | #
|
||||
# | | | T| | | | | #
|
||||
# l__j l_____jl__j__j l__j #
|
||||
# #
|
||||
##### #####
|
||||
# Repeat commands! #
|
||||
##################
|
||||
|
||||
import errno, os, subprocess, sys, time
|
||||
from optparse import OptionParser
|
||||
|
||||
|
||||
interval = 1.0
|
||||
command = 'true'
|
||||
clear = True
|
||||
get_paths = lambda: set()
|
||||
verbose = True
|
||||
dynamic = False
|
||||
paths_command = None
|
||||
|
||||
USAGE = """\
|
||||
usage: %prog [options] COMMAND
|
||||
|
||||
COMMAND should be given as a single argument using a shell string.
|
||||
|
||||
A list of paths to watch should be piped in on standard input.
|
||||
|
||||
For example:
|
||||
|
||||
find . | peat './test.sh'
|
||||
find . -name '*.py' | peat 'rm *.pyc'
|
||||
find . -name '*.py' -print0 | peat -0 'rm *.pyc'
|
||||
|
||||
If --dynamic is given, a command to generate the list should be piped in
|
||||
on standard input instead. It will be used to generate the list of files
|
||||
to check before each run.
|
||||
|
||||
This command must be quoted properly, and this can be tricky. Make sure
|
||||
you know what you're doing.
|
||||
|
||||
For example:
|
||||
|
||||
echo find . | peat --dynamic './test.sh'
|
||||
echo find . -name '*.py' | peat --dynamic 'rm *.pyc'
|
||||
"""
|
||||
|
||||
|
||||
def log(s):
|
||||
if verbose:
|
||||
print s
|
||||
|
||||
def die(s):
|
||||
sys.stderr.write('ERROR: ' + s + '\n')
|
||||
sys.exit(1)
|
||||
|
||||
def check(paths):
|
||||
cutoff = int(time.time() - interval)
|
||||
for p in paths:
|
||||
try:
|
||||
if os.stat(p).st_mtime >= cutoff:
|
||||
return True
|
||||
except OSError, e:
|
||||
# If the file has been deleted since we started watching, don't
|
||||
# worry about it.
|
||||
if e.errno == errno.ENOENT:
|
||||
pass
|
||||
else:
|
||||
raise
|
||||
return False
|
||||
|
||||
def run():
|
||||
log("running: " + command)
|
||||
subprocess.call(command, shell=True)
|
||||
|
||||
def build_option_parser():
|
||||
p = OptionParser(USAGE)
|
||||
|
||||
# Main options
|
||||
p.add_option('-i', '--interval', default=None,
|
||||
help='interval between checks in milliseconds',
|
||||
metavar='N')
|
||||
p.add_option('-I', '--smart-interval', dest='interval',
|
||||
action='store_const', const=None,
|
||||
help='determine the interval based on number of files watched (default)')
|
||||
p.add_option('-d', '--dynamic', default=False,
|
||||
action='store_true',
|
||||
help='take a command on standard input to generate the list of files to watch')
|
||||
p.add_option('-D', '--no-dynamic', dest='dynamic',
|
||||
action='store_false',
|
||||
help='take a list of files to watch on standard in (default)')
|
||||
p.add_option('-c', '--clear', default=True,
|
||||
action='store_true', dest='clear',
|
||||
help='clear screen before runs (default)')
|
||||
p.add_option('-C', '--no-clear',
|
||||
action='store_false', dest='clear',
|
||||
help="don't clear screen before runs")
|
||||
p.add_option('-v', '--verbose', default=True,
|
||||
action='store_true', dest='verbose',
|
||||
help='show extra logging output (default)')
|
||||
p.add_option('-q', '--quiet',
|
||||
action='store_false', dest='verbose',
|
||||
help="don't show extra logging output")
|
||||
p.add_option('-w', '--whitespace', default=None,
|
||||
action='store_const', dest='sep', const=None,
|
||||
help="assume paths on stdin are separated by whitespace (default)")
|
||||
p.add_option('-n', '--newlines',
|
||||
action='store_const', dest='sep', const='\n',
|
||||
help="assume paths on stdin are separated by newlines")
|
||||
p.add_option('-s', '--spaces',
|
||||
action='store_const', dest='sep', const=' ',
|
||||
help="assume paths on stdin are separated by spaces")
|
||||
p.add_option('-0', '--zero',
|
||||
action='store_const', dest='sep', const='\0',
|
||||
help="assume paths on stdin are separated by null bytes")
|
||||
|
||||
return p
|
||||
|
||||
|
||||
def _main():
|
||||
if dynamic:
|
||||
log("Running the following command to generate watch list:")
|
||||
log(' ' + paths_command)
|
||||
log('')
|
||||
|
||||
log("Watching the following paths:")
|
||||
for p in get_paths():
|
||||
log(' ' + p)
|
||||
log('')
|
||||
log('Checking for changes every %d milliseconds.' % int(interval * 1000))
|
||||
log('')
|
||||
|
||||
run()
|
||||
|
||||
while True:
|
||||
time.sleep(interval)
|
||||
if check(get_paths()):
|
||||
if clear:
|
||||
subprocess.check_call('clear')
|
||||
run()
|
||||
|
||||
def smart_interval(count):
|
||||
"""Return the smart interval to use in milliseconds."""
|
||||
if count >= 50:
|
||||
return 1000
|
||||
else:
|
||||
sq = lambda n: n * n
|
||||
return int(1000 * (1 - (sq(50.0 - count) / sq(50))))
|
||||
|
||||
def _parse_interval(options):
|
||||
global get_paths
|
||||
if options.interval:
|
||||
i = int(options.interval)
|
||||
elif options.dynamic:
|
||||
i = 1000
|
||||
else:
|
||||
i = smart_interval(len(get_paths()))
|
||||
|
||||
return i / 1000.0
|
||||
|
||||
def _parse_paths(sep, data):
|
||||
if not sep:
|
||||
paths = data.split()
|
||||
else:
|
||||
paths = data.split(sep)
|
||||
|
||||
paths = [p.rstrip('\n') for p in paths if p]
|
||||
paths = map(os.path.abspath, paths)
|
||||
paths = set(paths)
|
||||
|
||||
return paths
|
||||
|
||||
def main():
|
||||
global interval, command, clear, get_paths, verbose, dynamic, paths_command
|
||||
|
||||
(options, args) = build_option_parser().parse_args()
|
||||
|
||||
if len(args) != 1:
|
||||
die("exactly one command must be given")
|
||||
|
||||
command = args[0]
|
||||
clear = options.clear
|
||||
verbose = options.verbose
|
||||
sep = options.sep
|
||||
dynamic = options.dynamic
|
||||
|
||||
if dynamic:
|
||||
paths_command = sys.stdin.read().rstrip()
|
||||
|
||||
if not paths_command:
|
||||
die("no command to generate watch list was given on standard input")
|
||||
|
||||
def _get_paths():
|
||||
data = subprocess.check_output(paths_command, shell=True)
|
||||
return _parse_paths(sep, data)
|
||||
|
||||
get_paths = _get_paths
|
||||
else:
|
||||
data = sys.stdin.read()
|
||||
paths = _parse_paths(sep, data)
|
||||
|
||||
if not paths:
|
||||
die("no paths to watch were given on standard input")
|
||||
|
||||
for path in paths:
|
||||
if not os.path.exists(path):
|
||||
die('path to watch does not exist: ' + repr(path))
|
||||
|
||||
get_paths = lambda: paths
|
||||
|
||||
interval = _parse_interval(options)
|
||||
|
||||
_main()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
import signal
|
||||
def sigint_handler(signal, frame):
|
||||
sys.stdout.write('\n')
|
||||
sys.exit(130)
|
||||
signal.signal(signal.SIGINT, sigint_handler)
|
||||
main()
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
#!/bin/bash
|
||||
offlineimap -q; notmuch new
|
||||
Reference in New Issue
Block a user