#!/bin/bash # # DİKKAT! BU BETİK OTOMATİK OLARAK ÜRETİLMİŞTİR; LÜTFEN DÜZENLEMEYİN! # # 19 önyükleme (boot) betiği → wget ondokuz.biz/x -qO-| bash # # Otomatik olarak belirlenemezse GitHub kullanıcı hesabı sorulur. # # wget ondokuz.biz/x -qO-| bash [sonra] # # DİKKAT! Bu betiği çalıştırmadan önce kişisel GitHub hesabınızda şu depodan # çoğaltarak (fork) elde edeceğiniz "x" isimli bir deponuz olmalıdır: # # https://github.com/19/x set -e # API ihracı için Bash gerekiyor. if [ -z "$BASH" ]; then printf >&2 "Lütfen bu programı Bash ile çalıştırın. Örneğin:\n\n" printf >&2 "\twget ondokuz.biz/x -qO- | bash\n" exit 1 fi # ============================================================================== # Sabiteler # ============================================================================== # hangi dizine kurulum yapılacak? readonly DESTDIR=$HOME # Orijin depo hangisi? readonly UPSTREAM='19/x' # program ismi readonly PROGNAME='kur' # x kitaplığı readonly LIBFILE='lib/x' # x yapılandırma dosyası readonly XRCFILE='.x' # x sürücü dizini readonly XRCDIR='etc/xrc' # gizli dosyaların konulacağı dizin readonly PRIVATEDIR='.private' # gizli sayılması gereken dizinler readonly PRIVATEDIRS="$PRIVATEDIR .ssh .gnupg Mail" # depo adı readonly REPOSITORY='x' # depo ilklenirken kullanılacak commit mesajı readonly REPOSITORY_INITIATED_MESSAGE='ilk' # inek (size demedim) readonly COWFILE='etc/asset/x.png' # Bu paketler en başta gerekiyor. # XXX Dikkat! Bunlar birer komut. readonly DEB_CORE=" curl git pdmenu sudo " # ============================================================================== # Yardımcılar # ============================================================================== # Bir kabukta yerleşik olarak bulunmasını istediğimiz işlevler # kabuk kitaplıkları için basit ithalat use() { local n="$1" p m [ -n "$n" ] || return 0 local oldifs="$IFS"; IFS=':' for p in ${SHLIB}; do for m in "${p}/${n}.sh" "${p}/${n}"; do if [ -r "$m" ]; then IFS="$oldifs" if [ -f "$m" ]; then . "$m" elif [ -d "$m" ]; then sourcedir "$m" fi return 0 fi done done IFS="$oldifs" return 1 } # verilen dizinde öneklenmiş dosyaları (öntanımlı tümü) ithal et sourcedir() { local directory="$1" if [ $# -gt 1 ]; then shift else set -- "" fi local prefix f for prefix in "${@:-}"; do for f in "${directory}/"${prefix}*; do case "${f}" in "${directory}/${prefix}"'*') break ;; esac for f in "${directory}/"${prefix}*; do . "${f}" done break done done } # verilen dizinde öneklenmiş dosyaları (öntanımlı tümü) listele listdir() { local directory="$1" if [ $# -gt 1 ]; then shift else set -- "" fi local prefix f for prefix in "${@:-}"; do for f in "${directory}/"${prefix}*; do case "${f}" in "${directory}/${prefix}"'*') break ;; esac for f in "${directory}/"${prefix}*; do echo "$f" done break done done } # komut PATH içinde var mı? hascommand() { local oldifs="$IFS"; IFS=':' local p for p in $PATH; do if [ -x "${p}/${*}" ] && [ -f "${p}/${*}" ]; then IFS="$oldifs" return 0 fi done IFS="$oldifs" return 1 } # PATH türünde değişkenlere ekleme yap mungedpath() { local path p where path="$1"; p="$2"; where="$3" case "$path" in *:$p:*|$p:*|*:$p|$p) echo "${path}" ;; *) case "$where" in after) echo "${path}${path:+:}${p}" ;; *) echo "${p}${path:+:}${path}" ;; esac ;; esac } # RedHat'in ilgili işlevi pathmunge() { PATH=$(mungedpath "$PATH" "$@") } # tercih edilen sırada bir program seç selectalternatives() { local prog prog=$(echo "$(eval echo \$$1)") if [ -n "$prog" ]; then case "$prog" in /*) [ -x "$prog" ] || prog= ;; *) hascommand $prog || prog= ;; esac elif [ $# -gt 1 ]; then local p shift for p; do case "$p" in /*) if [ -x "$p" ]; then prog=$p break fi ;; esac if hascommand $p; then prog=$p break fi done fi echo "$prog" } # güvenli şekilde yönlendirme yapılabilecek bir dosya oluştur touchsafe() { local file perm file="$1" perm="$2" [ -n "$perm" ] || perm=600 if (umask 077 && touch "$file") 2>/dev/null && [ -w "$file" ] && [ ! -L "$file" ]; then chmod "$perm" "$file" else echo >&2 "'$file' dosyası güvenli değil" exit 1 fi } # ilk argüman diğer argümanlarda geçiyor mu? has() { local first first="$1" [ $# -gt 1 ] || return 1 shift case " $* " in *" $first "*) return 0 ;; esac return 1 } # verilen niteliklerin herhangi biri var mı? anyattr() { local attr for attr; do has "$attr" $X_ATTR && return 0 done return 1 } # verilen niteliklerin tümü var mı? allattr() { local attr for attr; do has "$attr" $X_ATTR || return 1 done return 0 } # verilen nitelikleri ekle setattr() { local attr for attr; do X_ATTR="$X_ATTR $attr" done } # git ortam değişkenlerini (gerekiyorsa) ilkleyerek ithal et exportgit() { local name email user token if [ -z "$GIT_AUTHOR_NAME" ]; then name="$(git config --global --get user.name 2>/dev/null ||:)" [ -n "$name" ] || name="$X_NAME" [ -z "$name" ] || export GIT_AUTHOR_NAME="$name" fi if [ -z "$GIT_AUTHOR_EMAIL" ]; then email="$(git config --global --get user.email 2>/dev/null ||:)" [ -n "$email" ] || email="$X_EMAIL" [ -z "$email" ] || export GIT_AUTHOR_EMAIL="$email" fi if [ -z "$GIT_COMMITTER_NAME" ] && [ -n "$GIT_AUTHOR_NAME" ]; then export GIT_COMMITTER_NAME="$GIT_AUTHOR_NAME" fi if [ -z "$GIT_COMMITTER_EMAIL" ] && [ -n "$GIT_AUTHOR_EMAIL" ]; then export GIT_COMMITTER_EMAIL="$GIT_AUTHOR_EMAIL" fi if [ -z "$GITHUB_USER" ]; then user="$(git config --global --get github.user 2>/dev/null ||:)" [ -n "$user" ] || user=${GIT_AUTHOR_EMAIL%%@*} [ -z "$user" ] || export GITHUB_USER="$user" fi if [ -z "$GITHUB_TOKEN" ]; then token="$(git config --global --get github.token 2>/dev/null ||:)" if [ -z "$token" ] && [ -r "$HOME/.private/github" ]; then token=$(cat "$HOME/.private/github" ||:) fi [ -z "$token" ] || export GITHUB_TOKEN="$token" fi } # x ortam değişkenlerini anons et exportx() { PATH=$PATH:$X_PATH export PATH X_PATH X_ATTR X_EDITOR X_SHELL X_TERM X_SCREEN X_NAME X_EMAIL } # bulunulan ortamdaki (neredeyse) tüm işlevleri ihraç et exportmostf() { # Bash gerekli [ -n "$BASH" ] || return 0 export -f $( declare -F | while read _ _ name; do expr "$name" : '\(_*\|main\|*_\)' >/dev/null || echo "$name" done ) } # renkli ileti ortamını sıfırla unsetcolors() { COLS=80 CO_GOOD= CO_WARN= CO_BAD= CO_NORMAL= CO_HILITE= CO_BRACKET= CO_XBLUE= CO_XGREEN= CO_XPINK= CO_XGREY= } # renkli iletileri ve uçbirim genişliğini hazırla setcolors() { COLS=${COLUMNS:-0} [ $COLS -eq 0 ] && COLS=$( set -- $(stty size /dev/null); echo ${2:-0} ) ||: [ $COLS -gt 0 ] || COLS=80 CO_GOOD='\033[32;01m' CO_WARN='\033[33;01m' CO_BAD='\033[31;01m' CO_HILITE='\033[36;01m' CO_BRACKET='\033[34;01m' CO_NORMAL='\033[0m' CO_XBLUE='\033[38;5;111m' CO_XGREEN='\033[38;5;120m' CO_XPINK='\033[38;5;198m' CO_XGREY='\033[38;5;250m' } # alt kabuklara renkleri ihraç et exportcolors() { export COLS export \ CO_GOOD \ CO_WARN \ CO_BAD \ CO_HILITE \ CO_BRACKET \ CO_NORMAL \ CO_XBLUE \ CO_XGREEN \ CO_XPINK \ CO_XGREY } # 8 bit ANSI renk kodunu üret color256() { echo -ne "\[\033[38;5;$1m\]"; } # iletiyi stderr'de görüntüle message() { printf -- "$*\n" | fold -s -w ${COLS:-80} >&2 } # iletiyi satır sonu olmadan stderr'de görüntüle messagen() { printf -- "$*" | fold -s -w ${COLS:-80} >&2 } # uyarı iletisi cry() { message_ "${CO_WARN}${*}${CO_NORMAL}" } # hata iletisi die() { message_ "${CO_BAD}${*}${CO_NORMAL}" exit 19 } initcolors() { # renkli iletiler kullanılsın mı? case "${NOCOLOR:-false}" in yes|true) unsetcolors ;; no|false) setcolors exportcolors ;; esac } # öngörülemeyen yazılım hatası iletisi bug() { message_ "$@" cry "Bu bir yazılım hatası, lütfen raporlayın." exit 70 } # renkli bir ileti say() { message_ "${CO_GOOD}${*}${CO_NORMAL}" } # eksik deb paketleri missingdeb() { local pkg missing for pkg; do if [ -z "$(dpkg-query -W -f='${Installed-Size}' "$pkg" 2>/dev/null ||:)" ]; then missing="$missing $pkg" fi done echo $missing } # deb paket(ler)i kurulu mu? hasdeb() { [ -z "$(missingdeb $*)" ] } # eksik ruby gem paketleri missinggem() { hascommand gem || bug "ruby gem kurulu değil" local pkg missing= for pkg; do if ! gem query -i -n '^'"$pkg"'$' >/dev/null 2>&1; then missing="$missing $pkg" fi done echo $missing } # ruby gem paket(ler)i kurulu mu? hasgem() { [ -z "$(missinggem $*)" ] } # kurulu deb paketi verilen sürümden daha mı eski hasolddeb() { local pkg version [ $# -gt 0 ] || return 0 pkg="$1"; version="$2" set -- $(dpkg-query -W "$pkg" 2>/dev/null ||:) if [ -z "$2" ]; then # paket kurulu değilse "true", yani olmayan paket eski bir paket return 0 elif [ -z "$version" ]; then # sürüm verilmemiş ama paket varsa "false", yani sürüm önemsiz return 1 fi # aksi halde karşılaştır dpkg --compare-versions "$2" lt "$version" } # verilen deb paketlerinin kurulu olduğuna emin ol ensuredeb() { local missing=$(missingdeb "$@") [ -z "$missing" ] || die "Devam etmeniz için şu paketlerin kurulması gerekiyor:" $missing } # verilen ruby gem paketlerinin kurulu olduğuna emin ol ensuregem() { local missing=$(missinggem "$@") [ -z "$missing" ] || die "Devam etmeniz için şu gem paketlerinin kurulması gerekiyor: " $missing } # kullanıcı ayrıcalıklı mı? isprivileged() { local g if [ $(id -u) -eq 0 ]; then return 0 else for g in $(groups); do case "$g" in sudo|admin|wheel|staff) return 0 ;; esac done fi return 1 } # sudo gerektiren işlemlerin öncesinde sudo parolası zaman aşımını tazele sudostart() { if [ $(id -u) -ne 0 ]; then cry "Yönetici hakları gerekecek; sudo parolası sorulabilir." local prompt=${*:-'Lütfen "%u" için parola girin: '} if ! sudo -v -p "$prompt"; then die "Parolayı hatalı giriyorsunuz veya yönetici olma yetkiniz yok!" fi fi } # sudo gerektiren bir işleme teşebbüs sudoattempt() { if [ $(id -u) -ne 0 ]; then if ! isprivileged; then cry "Yönetici yetkisinde olan bir işlem yapmak üzeresiniz. " \ "Fakat görüldüğü kadarıyla bu sistemde yöneticilerin dahil" \ "olduğu bir grupta (ör. sudo, admin, wheel) değilsiniz." if yesno "Buna rağmen yönetim yetkileri istemekte" \ "kararlı mısınız (sudo parolası istenecek)?" h; then die "İşleme son verildi." fi fi sudostart fi } # ilklendirilmemiş bir değişken mi? isnull() { [[ ! ${!1} && ${!1-_} ]] } # güvenli geçici dizin oluştur unset TEMPDIRS_ usetempdir() { local tempname="$1" keeptemp="$2" local prefix="$PROGNAME" [ -n "$prefix" ] || prefix=${0##*/} # As a security measure refuse to proceed if mktemp is not available. [ -x /bin/mktemp ] || die "'/bin/mktemp' bulunamadı; sonlanıyor." local tempdir="$(/bin/mktemp -d -t ${prefix}.XXXXXXXX)" || die "mktemp hata döndü" [ -d "$tempdir" ] || die "geçici bir dizin oluşturulamadı" if isnull TEMPDIRS_; then trap ' exitcode=$? [ -z "$TEMPDIRS_" ] || rm -rf -- "${TEMPDIRS_[@]}" unset TEMPDIRS_ exit $exitcode ' EXIT HUP INT QUIT TERM fi eval $(echo "$tempname=\"$tempdir\"") [ -n "$keeptemp" ] || TEMPDIRS_+=("$tempdir") } # git deposunu denetle ve tepe dizine çık ensuretopgitdir() { local up if ! up="$(git rev-parse --show-cdup 2>/dev/null)"; then die "Çalışma dizini bir git deposu değil" fi [ -z "$up" ] || cd "$up" } # ayrıntılı ileti if [ -n "$VERBOSE" ]; then verbose() { message_ "$@"; } else verbose() { :; } fi # iletilerde ileti kaynağı isteniyorsa ekle if [ -n "$ERROR_MESSAGE_DOMAIN" ]; then message_ () { message "${ERROR_MESSAGE_DOMAIN}: $*" } else message_ () { message "$*" } fi initcolors # check if console is interactive isinteractive() { tty -s 2>/dev/null } # öntanımlı değeri bekleterek kullanıcıdan girdi iste ask() { local prompt="$1" local default="$2" local validate="$3" must-non-empty() { if [ -z "$REPLY" ]; then printf "${CO_BAD}Girdi boş olmamalı.${CO_NORMAL}\n" return 1 fi } while :; do unset REPLY if [ -n "$default" ]; then printf "${CO_HILITE}${prompt} ${CO_NORMAL}[${CO_BRACKET}$default${CO_NORMAL}]? " read -e REPLY /dev/null && ! $validate; then continue fi break done # cevap REPLY değişkeninde } # doğrulayarak güvenli şekilde parola sor asksecret() { local prompt="$1" local onverify="$2" local entered asksecret_() { local prompt="$1" unset REPLY printf "${CO_HILITE}${prompt}${CO_NORMAL}? " stty -echo get() { curl -s -k "$@" } # Standart girdideki JSON verisinden değer oku # # Kullanım: [] json_get() { perl -e ' use strict; use warnings; use feature qw(say); use open qw(:std :utf8); use Encode qw(encode_utf8); use JSON qw(decode_json); my $json = do { local $/; }; die "Empty json content!\n" unless defined $json; $json = encode_utf8($json); my ($decoded_json, @stack) = (decode_json($json), ()); while (@ARGV) { push @stack, (my $key = shift @ARGV); unless (exists $decoded_json->{$key}) { $key = join ".", @stack; die "no key: $key\n"; } $decoded_json = $decoded_json->{$key}; } if ((my $ref = ref $decoded_json) eq "") { say $decoded_json; } elsif ($ref =~ m/[Bb]oolean/) { say $decoded_json ? "1" : "0"; } else { use Data::Dumper; $Data::Dumper::Terse = 1; $Data::Dumper::Deepcopy = 1; say Dumper $decoded_json; } ' "$@" } # REPLY değişkenindeki JSON verisinden oku # # Kullanım: [...] json_get_in_reply() { if [ -n "$REPLY" ]; then json_get "$@" <<<"$REPLY" 2>/dev/null fi } # Github API verisini REPLY'a oku # # Kullanım: # # API yolunda kullanılan '%s' dizgileri Github kullanıcı adıyle otomatik olarak # değiştirilir. # # Örnekler: # # gh_api_fetch repos/%s/%s.github.com # gh_api_fetch repos/%s/foo # gh_api_fetch repos/ecylmz/foo # gh_api_fetch() { local user path command : ${user:=$GITHUB_USER} : ${user:=$USER} unset REPLY path=$1 path=$(printf "$path" "$user") path=${path#/} shift REPLY=$(get "https://api.github.com/${path}" "$@" 2>/dev/null) || return } # Github API verisinden verilen değerleri oku # # Kullanım: [...] # # API yolunda kullanılan '%s' dizgileri Github kullanıcı adıyle otomatik olarak # değiştirilir. # # Örnekler: # # gh_api repos/%s/%s.github.com # gh_api repos/%s/foo source owner gravatar_id # gh_api repos/ecylmz/foo # gh_api() { path=$1 shift gh_api_fetch "$path" && json_get_in_reply "$@" } # apt-get sarmalayıcı (dikkat! güvensiz paketleri de kurar) xaptget() { local command [ $# -gt 0 ] || return 0 command="$1" shift sudo apt-get $command --option APT::Get::HideAutoRemove=1 \ --quiet --yes --allow-unauthenticated \ --force-yes --no-install-recommends --ignore-missing "$@" } # aptitude sarmalayıcı (dikkat! güvensiz paketleri de kurar) xaptitude() { # Paket kurulumu için bunu tercih ediyoruz çünkü aptitude eksik paketleri # atlayarak kurulum yapabiliyor, bk. http://bugs.debian.org/503215 # Dikkat! Ubuntu'da aptitude standart olarak kurulu gelmiyor. local command [ $# -gt 0 ] || return 0 command="$1" shift sudo aptitude $command -f --quiet --assume-yes --allow-untrusted --without-recommends --safe-resolver "$@" } # Aptitude hata verdiğinde bir de APT ile dene aptitude_or_aptget() { xaptitude "$@" || xaptget "$@" } # deb paketlerini hata halinde tekrar deneyerek kur installdebs() { local message="$1" shift ||: say "${message}..." local try=2 while [ $try -gt 0 ]; do err=0 aptitude_or_aptget install "$@" || err=$? # hata yoksa çık [ $err -ne 0 ] || break cry "Bazı Deb paketlerinin kurulumunda hata oluştu. " \ "Tekrar denenerek kuruluma devam edilecek..." try=$(($try - 1)) done } # adresi verilen bir deb paketini indir ve kur debinstallfromurl() { local url deb url="$1" deb=$(mktemp) || die "Geçici dosya oluşturulamadı" if wget "$url" -O"$deb" 2>/dev/null; then if [ ! -f "$deb" ]; then echo >&2 "$url adresinden bir dosya indirilemedi." return 1 fi if [ -n "$(which file 2>/dev/null ||:)" ]; then case "$(file --mime-type $deb 2>/dev/null ||:)" in *:\ application/octet-stream) ;; *) echo >&2 "$url adresinden indirilen dosya bir ikili paket değil." return 1 ;; esac fi sudo dpkg -i "$deb" && return 0 echo >&2 "$url kurulurken hatayla karşılaşıldı; düzeltilecek." sudo apt-get -f install ||: fi return 1 } # debian paket deposu ekle adddebrepository() { local name repository distribution components keyurl [ $# -ge 4 ] || bug "adddebrepository: argüman sayısı eksik" name="$1" repository="$2" distribution="$3" components="$4" keyurl="$5" case "$distribution" in ""|-) distribution=$(lsb_release -s -c 2>/dev/null ||:) ;; esac case "$components" in ""|-) components='main' ;; esac case "$repository" in http:*|ftp:*) ;; *) repository="http://${repository}" ;; esac case "$keyurl" in http:*|ftp:*) ;; "") ;; *) keyurl="http://${keyurl}" ;; esac list=/etc/apt/sources.list.d/$name.list if [ ! -f "$list" ]; then sudoattempt sudo sh -c "cat >$list </dev/null | sudo apt-key add - ||: fi # indeks güncellemesi gerekiyor return 0 fi return 1 } # wajig sarmalayıcı xwajig() { local command [ $# -gt 1 ] || return 0 command="$1" shift wajig -n -q -y $command "$@" } # gem sarmalayıcı (öntanımlı) xgem() { local command [ $# -gt 1 ] || return 0 command="$1" shift sudo gem $command --quiet --force --no-ri --no-rdoc "$@" } # gem sarmalayıcı (1.9 serisi ile) xgem191() { local command [ $# -gt 1 ] || return 0 command="$1" shift sudo gem1.9.1 $command --quiet --force --no-ri --no-rdoc "$@" } # gem paketlerini hata halinde tekrar deneyerek kur installgems() { local message="$1" shift ||: say "${message}..." local try=2 while [ $try -gt 0 ]; do err=0 xgem191 install "$@" || err=$? # hata yoksa çık [ $err -ne 0 ] || break cry "Bazı Gem paketlerinin kurulumunda hata oluştu. " \ "Tekrar denenerek kuruluma devam edilecek..." try=$(($try - 1)) done } # verilen dizgilerin ilk harflerini büyüt titlecase() { local s for s; do s="${s,,}" case "$s" in i*) s="İ${s:1:${#s}}" ;; ı*) s="I${s:1:${#s}}" ;; ğ*) s="Ğ${s:1:${#s}}" ;; ü*) s="Ü${s:1:${#s}}" ;; ş*) s="Ş${s:1:${#s}}" ;; ö*) s="Ö${s:1:${#s}}" ;; ç*) s="Ç${s:1:${#s}}" ;; *) s=${s^} ;; esac echo -n $s echo -n " " done } # hangi daldayız? git_current_branch() { local br br=$(git symbolic-ref -q HEAD) br=${br##refs/heads/} br=${br:-HEAD} echo "$br" } # dal mevcut mu? git_branch_exist() { git show-ref -q "$1" } # depo temiz durumda mı? git_is_clean() { { git diff-index HEAD --exit-code --quiet && git diff-index --cached HEAD --exit-code --quiet } >/dev/null 2>&1 || return 1 return 0 } # geçici olarak tüm değişiklikleri kaydet git_stash_push() { unset GIT_STASH_PUSHED if ! git_is_clean; then GIT_STASH_PUSHED=yes git stash save -q fi } # değişiklikleri geri yükle git_stash_pop() { if [ -n "$GIT_STASH_PUSHED" ]; then git stash pop -q fi } # verilen dala geçerek bir şey yap ve geri dön git_on_branch() { local br callback cur br="$1" callback="$2" shift 2 if git_branch_exist "$br"; then cur=$(git_current_branch) git_stash_push git checkout "$br" $callback "$@" git checkout "$cur" git_stash_pop else echo >&2 "$br dalı yok veya sorunlu" return 1 fi } # verilen dizin bir git çalışma kopyası mı? git_iswc() { case "$( LC_ALL=C GIT_DIR="$1/.git" /usr/bin/git rev-parse --is-inside-work-tree 2>/dev/null ||: )" in true) return 0 ;; false) return 1 ;; *) return 2 ;; esac } # deponun durumunu izle ve değişmişse raporla unset GIT_HEAD_FOLLOWED_ GIT_DIR_FOLLOWED_ git_head_follow() { local dir dir="${1:-.}" case "$dir" in */.git) ;; *) dir="${dir}/.git" ;; esac GIT_DIR_FOLLOWED_="$dir" GIT_HEAD_FOLLOWED_=$( git --git-dir="$GIT_DIR_FOLLOWED_" rev-parse HEAD 2>/dev/null ||: ) } git_head_unfollow() { local repo local ret=0 if isnull GIT_HEAD_FOLLOWED_ || isnull GIT_DIR_FOLLOWED_; then bug "İzlenen bir depo yok; önce git_head_follow çağrılmalı" fi case $( git --git-dir="$GIT_DIR_FOLLOWED_" rev-parse HEAD 2>/dev/null ||: ) in "$GIT_HEAD_FOLLOWED_") ret=1 ;; esac unset GIT_HEAD_FOLLOWED_ GIT_DIR_FOLLOWED_ return $ret } # depoyu güncelle ve değişiklik varsa (doğru dönerek) bildir git_pull_success_on_update() { local prev prev=$(git rev-parse HEAD 2>/dev/null ||:) GIT_MERGE_AUTOEDIT=no git pull "$@" || return 0 case "$(git rev-parse HEAD 2>/dev/null ||:)" in $prev) return 1 ;; esac } # GitHub # github ssh ile erişilebilir durumda mı? gh_writable() { # SSH kontrolünü sadece bir kere yapmak için sonucu sakla if [ -z "${IS_SSHABLE+X}" ]; then # SSH agent aktif değilse basitçe gerek şartları kontrol edeceğiz. if [ -z "$(ssh-add -l 2>/dev/null ||:)" ]; then # ~/.ssh dizini yok veya boşsa SSH kullanılamaz. if ! [ -d ~/.ssh ] || [ -r ~/.ssh/id_rsa ] || [ -r ~/.ssh/id_dsa ]; then IS_SSHABLE=no fi cry "SSH yetkilendirme ajanı aktif değil." cry "Yeni bir yetkilendirme ajanı oluşturulacak;" \ "lütfen öntanımlı SSH anahtarına ait parolayı girin." eval $(ssh-agent) ssh-add fi if [ -z "${IS_SSHABLE+X}" ]; then # Aksi halde daha yorucu ve çirkin bir kontrol gerekiyor. cry "SSH erişimi kontrol ediliyor (SSH parolası istenebilir)..." if ssh -T -o StrictHostKeyChecking=no git@github.com 2>&1 | egrep -q 'successfully authenticated'; then IS_SSHABLE=yes else IS_SSHABLE=no fi fi fi case "$IS_SSHABLE" in yes) return 0 ;; no) return 1 ;; esac } # verilen isimdeki değişkene yaz setv() { local name="$1" value="$2" eval $(echo "$name=\"$value\"") } # verilen isimdeki değişkeni oku getv() { local name="$1" echo "$(eval echo \$$name)" } # ağ bağlantısı var mı? hasnetwork() { local try # ağ bağlantısı? google dns cevap vermiyorsa 3. dünya savaşı # TODO gelecekte bu denetimi upstart veya startd ile yapmak lazım for try in 1 2 3 4 5; do /usr/bin/netcat -z -w 5 8.8.8.8 53 && return 0 done return 1 } # yaml alanı yaml() { ruby -ryaml -e 'h = YAML.load(STDIN); puts h[h.keys.first]['"$field"']' } # ============================================================================== # Bilinen sorunlar için küçük bir API # ============================================================================== # sorunu raporla knownproblem() { message_ "${CO_XGREY}Sorun: ${*}${CO_NORMAL}" } # sorun zaten yoksa raporla noproblem() { message_ "${CO_XGREY}Sorun yok.${CO_NORMAL}" exit 0 } # sorun düzeltilmişse raporla fixedproblem() { message_ "${CO_GOOD}Sorun düzeltildi.${CO_NORMAL}" } # sorunlu debian paketini yeni sürüme yükselt updateproblematicpackage() { local package version problem package="$1" version="$2" problem="$3" hasdeb "$package" || noproblem knownproblem "$problem" install-newer-deb "$package" "$version" && fixedproblem } # ============================================================================== # Ana işlevler # ============================================================================== # "workaround" ne anlama geliyor, buyurun örneği (maliyetli bir işlem) ensure_visible_colors() { local terminal notok # Bu yoksa yapılabilecek bir şey de yok. hascommand setterm || return 0 terminal=$( ps -p $( ps -p $( # bu prosesi çağıran kabuk prosesin numarası? ps -p $$ -o ppid= ) -o ppid= # o kabuk prosesi hangi numaralı proses çalıştırdı? ) -o cmd= # numarasını verdiğimiz prosesi oluşturan komut? ) case "$terminal" in # sorunlu terminaller *gnome-terminal) ;; # diğerlerini geç *) return 0 esac case "$DISTRO" in ubuntu) notok=0 # hayır ;; debian) notok=1 # kesin ;; *) notok=2 # belki message "Uçbirim renkleri ayarlanacak..." ;; esac if [ $notok -gt 0 ]; then local brightwhite normal default brightwhite='\033[37;01m' normal='\033[0m' default=h if [ $notok -gt 1 ]; then default=e fi message "-->${brightwhite}test test test${normal}<--" if ! yesno "Yukarıda oklar arasındaki yazıyı net okuyabiliyor musunuz?" $default; then setterm -term linux -inversescreen on 2>/dev/null ||: if ! yesno "Negatif uçbirim renkleriyle devam edilecek?" y; then setterm -term linux -inversescreen off \ 2>/dev/null ||: message "İsteğiniz üzerine kuruluma son" \ "verildi. Lütfen tekrar deneyin." exit 1 fi return 1 fi fi return 0 } # kur işlev ve değişkenlerini ihraç et exportapi() { X_REPOSITORY=${X:=$HOME} # değişkenler export DISTRO IS_NEWINSTALL TASKSEL TASKLIB HAS_APT_UPDATED DEBUG \ VERBOSE STAGINGDIR BACKUPDIR PRIVATEDIR XRCFILE X_REPOSITORY \ X_ATTR X_EMAIL X_NAME GITHUB_USER GITHUB_TOKEN # işlevler exportmostf } # kurulum görevini atla skiptask() { # Görev seçici çalıştırılmışsa görevi atlama. [ -z "$TASKSEL" ] || return 0 message_ "${CO_XPINK}Görev atlandı: $*${CO_NORMAL}" exit 0 } # görevleri dosya|başlık biçiminde listele taskitems() { local prefix path p task title [ -n "$TASKLIB" ] || bug "TASKLIB tanımlı değil" [ -n "$1" ] || bug "Görev dosyası öneki tanımlanmamış" prefix="$1" shift ||: if [ $# -ge 1 ]; then local name="$1" filteritems() { ls ${1}/${prefix}* 2>/dev/null | egrep -s "$name" ||: } else filteritems() { ls ${1}/${prefix}* 2>/dev/null ||: } fi IFS=: path=($TASKLIB) unset IFS # Aynı isimde görevleri belirlemek için denetim tablosu. declare -A seen for p in ${path[@]}; do for task in $(filteritems "$p"); do case "$task" in *\|*) bug "Hatalı görev dosyası adı: $task" ;; esac title="${task##*/}" title="${title#*-}" title="${title//-/ }" if [ -z "${seen[${title}]}" ]; then # Anahtar olarak dosya başlığını kullan. seen["${title}"]=yes title=$(titlecase $title) echo "${task}|${title}" fi done done } # görev dosyasını çalıştır execline() { local task shebang interpreter task="$1" if [ -x "$task" ]; then echo "'$task'" else shebang=$(head -n 1 "$task") case "$shebang" in \#!) interpreter=${shebang##\#!} ;; \#\ !) interpreter=${shebang##\# !} ;; *) interpreter=/bin/bash ;; esac echo "$interpreter '$task'" fi } # görev dosyası ve başlığına uygun pdmenu satırını üret taskmenuitem() { local task title key flag task="$1" title="$2" key="$3" flag="$4" [ -z "$key" ] || key="_${key} " [ -n "$flag" ] || flag="pause" echo exec:${key}${title}:${flag}:$(execline "$task") } # kurulum görevini tanıt taskintroduce() { message_ "${CO_XBLUE}${*}${CO_NORMAL}" } # görev dosyasını görevi tanıtarak çalıştır taskinvoke() { local task title task="$1" title="$2" shift 2 args="$@" taskintroduce $title execl=$(execline "$task") verbose "===> ${execl}" eval $execl $args || cry "${task} görevi hatayla sonlandı." } # dosya|başlık satırını ayrıştırarak verilen işlevi çalıştır dotask() { local taskline callback taskline="$1" callback="$2" shift 2 args="$@" ifssave=$IFS IFS='|' set -- $taskline task="$1" title="$2" IFS="$ifssave" $callback "$task" "$title" $args } # dinamik olarak pdmenu menüsü oluştur makemenu() { local category num item category="$1" num=97 # 'a' harfi taskitems "$category" | while read item; do key=$(printf \\$(printf '%03o' $num)) dotask "$item" taskmenuitem "$key" num=$(($num + 1)) done } # görev menüsü taskmenu() { local last last=$(git log -n1 --format='%h' --merges 2>/dev/null ||:) [ -n "$last" ] || last="0" _makegrp() { cat <<-EOF group:$1 exec::makemenu:\ echo "menu:$2:$3:$4"; \ bash -c 'makemenu $5'; \ echo "nop"; \ echo "exit:_Başa dön" show:::$2 remove:::$2 endgroup EOF } exportapi; { cat <<-EOF title:19/x - ${last} menu:main:Görevler:© 2011 Recai Oktaş EOF _makegrp "_Kurulum Görevleri" \ "installation" \ "Kurulum Görevleri" \ "İlk kurulumda çalıştırılmış görevler" \ 0 _makegrp "_Genel Görevler" \ "general" \ "Genel Görevler" \ "Genel amaçlı görevler" \ 1 if isprivileged; then _makegrp "_Yönetim Görevleri" \ "administration" \ "Yönetim Görevleri" \ "Yönetici izini gerektiren görevler" \ 2 fi _makegrp "_Bilinen Sorunlar" \ "hack" \ "Bilinen Sorunlar" \ "Bilinen sorunları düzeltmeye yönelik görevler" \ 7 echo "nop" _makegrp "_Depo İşlemleri" \ "repository" \ "Depo İşlemleri" \ "19/x deposuyla ilgili işlemler" \ 9 echo "exec:Yardım (F1)::x-tmux-man 19-x" echo "exit:Çıkış (q veya Esc)" } | pdmenu - --color } # verilen kategori ve isimdeki görevleri çalıştır taskrun() { exportapi taskitems "$@" | while read item; do dotask "$item" taskinvoke done } # kurulum görevlerinin (0 ve 7 kategorileri) tümünü çalıştır taskrun07() { local categories category categories="0" # baz ve sunucu kurulumlarında elle müdahale anyattr base server || categories="$categories 7" exportapi for category in $categories; do taskitems "$category" | while read item; do dotask "$item" taskinvoke done done } # ilklendirme dosyalarını depo köküne çek installrc() { local rcdir rcdir=$1 # skel dizinindekiler olduğu gibi cp -a "${rcdir}/skel/." . # diğerlerini sembolik olarak bağla perl -e ' use strict; use warnings; use File::Find; use File::Spec; use File::Basename; my $rcdir = $ARGV[0]; my @files; find({ no_chdir => 1, wanted => sub { return if -d $_; # Şablon dizinindekileri atla return if m!^\E${rcdir}\Q/skel/!x; push @files, $_; }, }, $rcdir); for my $file (@files) { my $target = File::Spec->abs2rel($file, $rcdir); my $mode = sprintf "%04o", (stat(dirname($file)))[2] & 07777; my $directory = dirname($target); my $relsource = File::Spec->abs2rel($file, $directory); system("install", "-d", "-m", $mode, $directory); system("ln", "-sf", $relsource, $target); } ' "$rcdir" } # esas oğlan go() { local f d moo # --------------------------------------------------------------------- # Ön kurulum # --------------------------------------------------------------------- # Gerekli paketleri kontrol et, bir nedenle kuramazsak devam etme. # XXX Bu denetimi paket adıyla program adının aynı olması varsayımı # altında programın varlığına bakarak yapıyoruz. dpkg-query yoluyla # bir paketin kurulu olup olmadığını denetlemek çok maliyetli. local p missing for p in $DEB_CORE; do if ! hascommand "$p"; then missing="$missing $p" fi done # Artık perl ile JSON ayrıştırması yapıyoruz. Bu modül perl # 5.14 ile standart geliyor. Ama eski sürümler için gerekli # paketi kurmalıyız. if ! perl -e 'use JSON' 2>/dev/null; then missing="$missing libjson-perl" fi if [ -n "$missing" ]; then case "$missing" in *sudo*) die "sudo paketi kurulu gözükmüyor. " \ "Lütfen önce bu paketi elle kurun." ;; esac say "'$(echo $missing)' paket(ler)i kurulu değil. " \ "Önce bunlar kurulacak." sudoattempt say "Paket indeksleri güncelleniyor..." xaptget update ||: HAS_APT_UPDATED=yes xaptget install $missing # Kurulum için bize gereken tüm paketler artık kurulmuş olmalı. fi # Bu betik kurulum sonrasında da çalıştırılabilir. if [ -n "$X" ]; then case "$0" in ""|bash|*/bash) if ! yesno "Yeni baştan kurulum mu yapmak istiyorsunuz?" e; then TASKSEL=yes fi ;; *) TASKSEL=yes ;; esac fi readonly TASKSEL # Sadece kurulum görevleri isteniyor. if [ -n "$TASKSEL" ]; then cd "$DESTDIR" readonly STAGINGDIR="$DESTDIR" taskmenu exit $? fi if [ -d "${DESTDIR}/.git" ]; then say "Kurulum dizini '$DESTDIR'da zaten" \ "bir Git deposu (eski bir kurulum?) var." if ! yesno "Kuruluma devam edilsin mi (hedef dosyalar yedeklenecek)?" h; then say "Kurulumdan çıkıldı." exit 0 fi fi # --------------------------------------------------------------------- # GitHub bilgisi topla # --------------------------------------------------------------------- # Github denetimleri nasıl pas geçilir? X_NO_SANITY_HINT="[Kurulumu zorlamak için X_NO_SANITY=yes]" if [ -z "$GITHUB_USER" ]; then while :; do local user ask "GitHub hesap adınız?" "$USER" user="$REPLY" if [ -z "$X_NO_SANITY" ] && ! gh_api_fetch "users/$user"; then cry "'$user' adında bir GitHub hesabı yok" if yesno "Tekrar denemek ister misiniz?"; then continue else die "Lütfen bir GitHub hesabı açın ve" \ "tekrar deneyin. $X_NO_SANITY_HINT" fi fi GITHUB_USER="$user" break done fi # Kısa bir rapor. say "GitHub hesabı olarak '$GITHUB_USER' kullanılacak." # --------------------------------------------------------------------- # Depoyu ara dizine klonla # --------------------------------------------------------------------- # Mevcut bilgilere göre hedef deponun varlığını kontrol et. if [ -z "$X_NO_SANITY" ] && ! gh_api_fetch "repos/%s/$REPOSITORY" 2>/dev/null; then die "Hesabınızda '$REPOSITORY' isimli bir depo mevcut değil." \ "Lütfen önce bu depoyu çoğaltarak oluşturun." \ "$X_NO_SANITY_HINT" fi if [ -z "$X_NO_SANITY" ]; then local parent=$( json_get_in_reply parent full_name 2>/dev/null ||: ) if [ -z "$parent" ]; then die "Hesabınızda bulunan '$REPOSITORY' deposu" \ "çoğaltılmış (fork edilmiş) bir depo değil." \ "$X_NO_SANITY_HINT" elif [ $parent != "$UPSTREAM" ]; then die "Hesabınızda bulunan '$REPOSITORY' deposu" \ "hatalı bir depodan ('$parent') çoğaltılmış." \ "Lütfen bu depoyu silin ve '$UPSTREAM' deposundan" \ "çoğaltma yapın. $X_NO_SANITY_HINT" fi fi # Şimdilik bir ara dizine klonla, salt okunur olarak (git:// şeması). usetempdir STAGINGDIR # bir nedenle hata olursa bu dizin çıkışta silinir if ! git clone \ "git://github.com/${GITHUB_USER}/${REPOSITORY}" \ "$STAGINGDIR"; then die "Depo klonlama başarısız. " \ "Geçici bir sorun olabilir, lütfen tekrar deneyin." fi # XXX Geçici dizindeyiz cd "$STAGINGDIR" # Doğru depo mu geldi? Basit denetim. [ -f "$LIBFILE" ] || die "Klonlanan depoda '$LIBFILE' dosyası yok. " \ "Doğru depoyu çoğalttığınıza emin misiniz?" # 19/x ortamını ilkle. X_HOME=$PWD . "$LIBFILE" || cry "$LIBFILE dosyasında sorun var; devam edilecek." # Bu depo acaba daha önce (bir başka kurulumda) ilklenmiş mi? # Ana yapılandırma dosyası depo kökünde ise evet. [ -f "$XRCFILE" ] || IS_NEWINSTALL=yes readonly IS_NEWINSTALL # --------------------------------------------------------------------- # Yeni kurulum # --------------------------------------------------------------------- # Bu yeni bir kurulum ise yapılacak işler var. if [ -n "$IS_NEWINSTALL" ]; then if anyattr base server; then die "Kısıtlı kullanıcı ortamına sahip bir makinede" \ "örneğin bir sunucu) yeni kurulum yapmaya" \ "çalışıyorsunuz. Lütfen yeni kurulumu daha uygun" \ "bir makinede (örneğin bir masaüstü" \ "makine) yapın." fi if ! gh_writable; then say "Bu bir ilk kurulum olduğundan ana depoya" \ "yazabilmeniz, yani GitHub hesabınıza bu" \ "makineden SSH erişimi yapabilmeniz" \ "gerekiyor. Fakat yapılan kontrole göre şu an" \ "bu erişimin gerçekleştirilemediği görülüyor. "\ "Bu eğer geçici bir sorun değilse bu makine için" \ "ssh-keygen'le anahtar üretmeniz ve ortak anahtar" \ "dosya içeriğini (~/.ssh/id_rsa.pub dosyası)" \ "hesabınıza kaydetmeniz gerekiyor. Lütfen bu" \ "konuyla ilgili olarak şu dokümanı okuyun," \ "uygulayın ve tekrar deneyin." \ "\n\n\thttp://help.github.com/linux-key-setup/\n\n" die "Kurulum sonlandırıldı." fi # rc dosyalarını depo köküne çek installrc "$XRCDIR" # Tepe seviyedekiler dışındaki her şeyi göz ardı et echo '/*' >.gitignore git add -f .gitignore for f in $(ls -A "."); do # Özel dizin de göz ardı edilmeli if ! has "$f" $PRIVATEDIRS; then echo "!/${f}" >>.gitignore fi done # Şimdi depoya ekle git add . fi # --------------------------------------------------------------------- # Depo referanslarını ayarla. # --------------------------------------------------------------------- local is_rw is_rw="$IS_NEWINSTALL" # yeni depolar daima SSH şeması kullanır if [ -z "$is_rw" ] && gh_writable && yesno "Bu makineden ana depoya gönderim yapacak mısınız?" h; then is_rw=yes fi if [ -n "$is_rw" ]; then git config remote.origin.url \ "git@github.com:${GITHUB_USER}/${REPOSITORY}" else cry "Depo salt-okunur olarak ayarlandı. Bu makinede depoda" \ "yaptığınız değişiklikleri GitHub'a gönderemezsiniz." fi git remote add upstream "git://github.com/${UPSTREAM}" say "Üst geliştirici referansı 'upstream' olarak ayarlandı. " \ "Depoyu güncellemek için lütfen şu komutu kullanın:" \ "'git pull upstream master'" # --------------------------------------------------------------------- # Kurulum dizinine taşı # --------------------------------------------------------------------- # Yedeklerin alınacağı geçici dizini oluştur. usetempdir BACKUPDIR keeptemp # Kopyalanacak tepe seviyedeki dosya/dizinlere bak. for f in $(ls -A .); do local target skel target="${DESTDIR}/${f}" # uç durum: bogus izinli dosya/dizinleri düzelt if [ -e "$target" ] && [ ! -w "$target" ]; then cry "${target} dosya/dizininin hatalı" \ "izinleri düzeltilecek..." sudoattempt sudo chown ${USER:=$(id -u)}: "$target" fi if [ -f "$target" ] || [ -L "$target" ]; then skel="/etc/skel/${f}" if { # hedef dosya sıfır boyutlu mu? [ ! -s "$target" ] } || { # hedef dosya ile kaynak aynı mı? cmp -s "$f" "$target" } || { # hedef dosya /etc/skel'den mi gelmiş? [ -f "$target" ] && [ -f "$skel" ] && cmp -s "$skel" "$target" }; then # hedefi yedeklemek gerekmiyor rm -rf "$target" verbose "mevcut hedef dosya '$target' silindi" else # aksi halde yedekle mv "$target" "${BACKUPDIR}/" verbose "mevcut hedef dosya '$target'" \ "'$BACKUPDIR' dizinine taşındı" fi # Hedef bir dizinse biraz daha özel davran. elif [ -d "$target" ]; then case "$f" in .config) # XDG yapılandırma dizinini taşıma. Sadece # mevcut dosyanın üzerine yaz. ;; *) mv "$target" "${BACKUPDIR}/" verbose "mevcut hedef dizin '$target'" \ "'$BACKUPDIR' dizinine taşındı" ;; esac fi done # Üzerine yazarak kopyala. cp -a . "$DESTDIR" # Artık hedef dizindeyiz. cd "$DESTDIR" # --------------------------------------------------------------------- # Kurulum görevlerini çalıştır # --------------------------------------------------------------------- # Paket indeksleri daima güncel olmalı. if [ -z "$HAS_APT_UPDATED" ]; then say "Paket indeksleri güncelleniyor..." sudoattempt xaptget update ||: HAS_APT_UPDATED=yes fi # XXX Kurulum dizinde kurulum görevlerini çalıştır. say "Kurulum görevleri çalıştırılıyor..." taskrun07 # --------------------------------------------------------------------- # Yeni kurulumu kaydet # --------------------------------------------------------------------- if [ -n "$IS_NEWINSTALL" ]; then if ! git commit -a -m "$REPOSITORY_INITIATED_MESSAGE"; then die "Depo değişiklikleri kaydedilirken hata oluştu. "\ "Lütfen kurulumu tekrar deneyin." fi cry "Depo değişiklikleri GitHub'a gönderiliyor. Sunucu"\ "anahtarını onaylamanız ve parola girmeniz istenebilir..." if ! git push origin master; then die "GitHub gönderimi başarısız; kuruluma devam" \ "edilemeyecek. Bu geçici bir bağlantı sorunu" \ "olabilir. Lütfen kurulumu tekrar deneyin." fi fi # --------------------------------------------------------------------- # Ekstra güvenlik önlemleri # --------------------------------------------------------------------- # Gizli dizin ve dosyalardan emin ol. for d in $PRIVATEDIRS; do [ -d "$d" ] || continue chmod 700 "$d" for f in $(ls -A "$d"); do [ -f "${d}/${f}" ] || continue chmod 600 "${d}/${f}" done done # --------------------------------------------------------------------- # Kurulumu sonlandır # --------------------------------------------------------------------- say "Kurulum sonlandırılıyor..." # Yenilere bir hoşgeldin. if [ -n "$IS_NEWINSTALL" ]; then if [ -d "$PRIVATEDIR" ]; then say "Gizlilik gerektiren dosyalar için ${PRIVATEDIR}" \ "dizinini kullanın. Dikkat! Bu dizini"\ "depoya eklemeyin." fi fi # Yedeklenen dosyalar varsa varlığından bahset. if ! rmdir $BACKUPDIR 2>/dev/null; then cry "Eski bazı dosyalar '$BACKUPDIR' dizinine yedeklendi. " \ "Bunları kontrol edin." fi moo="Kurulum tamamlandı! Lütfen bilgisayarı yeniden başlatın." if [ -n "$DISPLAY" ] && [ -x "/usr/games/xcowsay" ]; then local image opts if [ -x /usr/bin/pngtopnm ] && [ -f "$COWFILE" ] && image=$(/bin/mktemp); then /usr/bin/pngtopnm "$COWFILE" >"$image" opts="--image $image" fi 2>/dev/null ||: /usr/games/xcowsay $opts "$moo" 2>/dev/null ||: [ -z "$image" ] || rm -f "$image" elif [ -x "/usr/games/cowsay" ]; then /usr/games/cowsay -W 60 "$moo" 2>&1 fi ||: # Bir de konsolda. cry "$moo" } main() { # Yönetici hakkını almak kolay (sudo), vermek zor. [ $(id -u) -ne 0 ] || die "Bu betiği başlangıçta root olarak çalıştırmamalısınız!" # hmm, ne dediğimi ben de tam bilmiyorum ama bunu garanti sağlayalım ;-) tty -s || tty -s /dev/null)" in *[Uu]buntu*) DISTRO=ubuntu ;; *[Dd]ebian*) DISTRO=debian ;; *[Mm]int*) DISTRO=mint ;; *) DISTRO=unsupported die "Üzgünüm bu dağıtım şimdilik desteklenmiyor." ;; esac ;; *) die "Üzgünüm şimdilik sadece Linux destekleniyor." ;; esac readonly DISTRO # Debian ve başka bazı dağıtımlarda gnome-terminal öntanımlı olarak # beyaz arka planla geliyor. Kullanıcı bu betiği böyle bir terminal # üzerinde çalıştırıyorsa renklerin bir kısmı zor seçiliyor. Bu durumu # algıla ve arka plan rengini değiştir. if ! ensure_visible_colors; then # alt kabukta çalıştıralım çünkü renk düzeltmesi için trap # kullanamıyoruz (trap usetempdir tarafından kullanılıyor) ( go "$@" ) || errcode=$? setterm -term linux -inversescreen off 2>/dev/null ||: exit $errcode # hatalı dönüş kodlarına saygı duy else go "$@" fi } main "$@" # vim:ft=sh