From 03fcc1cbaed6509fcc378b9b7b880f48ad08c110 Mon Sep 17 00:00:00 2001 From: Guillaume Dott Date: Thu, 6 Apr 2017 14:23:57 +0200 Subject: [PATCH] bin: Add some more or less useful bin --- bin/git-game | 116 +++++++++++++++++++++++++++++ bin/git-release | 55 ++++++++++++++ bin/hr | 51 +++++++++++++ bin/nasa-iotd | 38 ++++++++++ bin/old-git-release | 175 ++++++++++++++++++++++++++++++++++++++++++++ bin/pipes.sh | 108 +++++++++++++++++++++++++++ 6 files changed, 543 insertions(+) create mode 100755 bin/git-game create mode 100755 bin/git-release create mode 100755 bin/hr create mode 100755 bin/nasa-iotd create mode 100755 bin/old-git-release create mode 100755 bin/pipes.sh diff --git a/bin/git-game b/bin/git-game new file mode 100755 index 0000000..503eb61 --- /dev/null +++ b/bin/git-game @@ -0,0 +1,116 @@ +#!/usr/bin/ruby + +longest_streak = streak = 0 + +# -- Exit gracefully -- +Signal.trap("INT") { + puts "\nLongest streak: #{longest_streak}" + exit 0 +} + +def print_header + puts "----------------------------------------------------------" + puts " THE GIT GAME " + puts "----------------------------------------------------------" + puts "Welcome! The goal of the git game is to guess committers" + puts "based on their commit messages.\n\n" +end + +def print_help + puts "----------------------------------------------------------" + puts " USAGE " + puts "----------------------------------------------------------" + puts "git game [extra git log options]" + puts "EX: git game --after={2014-08-08}" + puts "(This script already uses --no-merges and --pretty." + puts "For more valid options see: http://gitref.org/inspect/)" +end + +# -- Usage Text -- +if ARGV.count > 0 && (input = ARGV.shift) == 'help' + print_header + print_help + exit 0 +end + +# -- Parse commits -- +COMMIT_DELIMITER = "XXXCOMMITXXX" +FIELD_DELIMITER = "|||" + +commit_format = ["%an", "%ar", "%B"].join(FIELD_DELIMITER) + +raw_commits = `git log --no-merges --pretty="#{COMMIT_DELIMITER}#{commit_format}" #{input if input}`.split("#{COMMIT_DELIMITER}") +commits = [] +raw_commits.each do |c| + next if c.strip.empty? + + fields = c.split(FIELD_DELIMITER) + commits << {:author => fields[0], :date => fields[1], :message => fields[2]} +end + +committers = commits.map { |c| c[:author] }.compact.uniq + +# -- Show welcome message -- +system('clear') + +print_header +puts "You're playing in a repo with #{commits.size} commits and #{committers.size}" +puts "distinct committers.\n\n" + +committers.each do |committer| + puts committer +end + +puts "Ready? PRESS ENTER TO START PLAYING (Ctrl-C to quit)" + +gets + +system('clear') + +# -- Game loop -- +NUM_CHOICE = 4 + +loop do + commit = commits.shuffle.pop + message = commit[:message] + author = commit[:author] + + next if message.nil? || message.empty? || author.nil? || author.empty? + + puts "(#{commit[:date]})\n" + puts "#{message.strip}\n\n" + puts + + choices = committers.sample(NUM_CHOICE) + if !choices.include?(author) + choices.pop + choices.push author + end + choices.shuffle! + + choices.each_with_index do |name, index| + puts "[#{index + 1}] #{name}" + end + + print "Who wrote it (current streak: #{streak})? " + + guess = gets.strip + + while guess.empty? || !guess.to_i.between?(1, NUM_CHOICE) + print "Who wrote it (current streak: #{streak})? " + guess = gets.strip + end + + if choices[guess.to_i - 1] == author + streak += 1 + puts "Got it!" + else + streak = 0 + puts "Actually, it was #{author}." + end + + longest_streak = [longest_streak, streak].max + + sleep 1 + system('clear') +end diff --git a/bin/git-release b/bin/git-release new file mode 100755 index 0000000..f65bb9a --- /dev/null +++ b/bin/git-release @@ -0,0 +1,55 @@ +#!/usr/bin/env ruby + +require 'date' + +begin + require 'cocaine' +rescue LoadError + puts "Cocaine gem not found, install it: 'gem install cocaine'" + exit +end + +module Release + class Git + REMOTE = 'origin' + RELEASE_BRANCH = 'master' + + def self.create + develop_branch = current_branch + + stash = Cocaine::CommandLine.new('git', 'stash create').run.chomp + Cocaine::CommandLine.new('git', 'reset --hard').run + + Cocaine::CommandLine.new('git', 'checkout :branch').run(branch: RELEASE_BRANCH) + Cocaine::CommandLine.new('git', 'merge --ff-only :branch').run(branch: develop_branch) + + Cocaine::CommandLine.new('git', 'tag -a -m :message :tag').run( + message: "Released by #{user}@#{hostname}", tag: "release-#{DateTime.now.strftime('%Y%m%dT%H%M%S')}") + + Cocaine::CommandLine.new('git', 'push --tags :remote :branch').run( + remote: REMOTE, branch: "#{RELEASE_BRANCH}:#{RELEASE_BRANCH}") + ensure + Cocaine::CommandLine.new('git', 'checkout :branch').run(branch: develop_branch) + Cocaine::CommandLine.new('git', 'stash apply :stash').run(stash: stash) unless stash.to_s.empty? + end + + def self.current_branch + branch = Cocaine::CommandLine.new('git', 'rev-parse --abbrev-ref HEAD').run.chomp + branch == 'HEAD' ? current_commit : branch + end + + def self.current_commit + Cocaine::CommandLine.new('git', 'rev-parse HEAD').run.chomp + end + + def self.user + Cocaine::CommandLine.new('id', '-un').run.chomp + end + + def self.hostname + Cocaine::CommandLine.new('hostname').run.chomp + end + end +end + +Release::Git.create diff --git a/bin/hr b/bin/hr new file mode 100755 index 0000000..b76a648 --- /dev/null +++ b/bin/hr @@ -0,0 +1,51 @@ +#!/usr/bin/env bash + +# The MIT License (MIT) +# +# Copyright (c) 2013 Gil Gonçalves +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +# the Software, and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +COLS="$(tput cols)" +if [[ "$COLS" -le 0 ]] ; then + COLS="${COLUMNS:-80}" +fi + +hr() { + local WORD="$1" + if [[ -n "$WORD" ]] ; then + local LINE='' + while (( ${#LINE} < "$COLS" )) + do + LINE="$LINE$WORD" + done + + echo "${LINE:0:$COLS}" + fi +} + +hrs() { + local WORD + + for WORD in "${@:-#}" + do + hr "$WORD" + done +} + +[ "$0" == "$BASH_SOURCE" ] && hrs "$@" diff --git a/bin/nasa-iotd b/bin/nasa-iotd new file mode 100755 index 0000000..562b5f2 --- /dev/null +++ b/bin/nasa-iotd @@ -0,0 +1,38 @@ +#!/usr/bin/env ruby + +require 'fileutils' +require 'tempfile' +require 'rss' +require 'uri' +require 'net/http' + +IMAGE_DIR = File.expand_path '~/pictures/nasa-iotd' +FEED_URL = 'http://www.nasa.gov/rss/dyn/lg_image_of_the_day.rss' + +CURRENT_FILE = File.join(IMAGE_DIR, 'current.jpg') +PREVIOUS_FILE = File.join(IMAGE_DIR, 'previous.jpg') +WALLPAPER_FILE = File.join(IMAGE_DIR, 'wallpaper.jpg') + +def download url, file + File.open(file, 'wb') { |f| f.write Net::HTTP.get(URI(url)) } + `convert #{file} -resize 1920x1080 -gravity center -background black -extent 1920x1080 #{file}` +end + +FileUtils.mkdir_p(IMAGE_DIR) unless File.directory?(IMAGE_DIR) + +feed = RSS::Parser.parse FEED_URL, false +today = feed.items.first.enclosure.url.sub('http:', 'https:') + +new = Tempfile.new('nasa-iotd').path + +download today, new + +unless File.exists?(CURRENT_FILE) && FileUtils.cmp(new, CURRENT_FILE) + FileUtils.mv CURRENT_FILE, PREVIOUS_FILE if File.exist?(CURRENT_FILE) + FileUtils.mv new, CURRENT_FILE +end + +download feed.items[1].enclosure.url.sub('http:', 'https:'), PREVIOUS_FILE unless File.exist?(PREVIOUS_FILE) + +`convert #{CURRENT_FILE} #{PREVIOUS_FILE} +append #{WALLPAPER_FILE}` +`feh --bg-tile #{WALLPAPER_FILE}` diff --git a/bin/old-git-release b/bin/old-git-release new file mode 100755 index 0000000..f9d0dae --- /dev/null +++ b/bin/old-git-release @@ -0,0 +1,175 @@ +#!/usr/bin/env ruby + +begin + require 'cocaine' +rescue LoadError + puts "Cocaine gem not found, install it: 'gem install cocaine'" + exit +end + +require 'yaml' + +module Release + class Version + attr_accessor :major, :minor, :patch + + VERSION_REGEX = /.*([0-9]+)\.([0-9]+)\.([0-9]+).*/ + + def self.load + [Ruby, Yaml].detect(&:check?).new + end + + def initialize + read + end + + def file + self.class::FILE + end + + def increment + if ENV.key?('VERSION') + self.version = ENV['VERSION'] + elsif ENV.key?('MAJOR') + increment_major + elsif ENV.key?('MINOR') + increment_minor + else + increment_patch + end + + self + end + + def increment_major + self.patch = 0 + self.minor = 0 + self.major += 1 + end + + def increment_minor + self.patch = 0 + self.minor += 1 + end + + def increment_patch + self.patch += 1 + end + + def next + dup.increment + end + + def version + "#{major}.#{minor}.#{patch}" + end + + def version=(version) + match = VERSION_REGEX.match version + + self.major = match[1].to_i + self.minor = match[2].to_i + self.patch = match[3].to_i + end + + def save + write + version + end + + class Ruby < Version + FILE = Dir.glob(File.join('lib', '*', 'version.rb')).first + REGEX = /VERSION\s*=\s*['"]([0-9]+)\.([0-9]+)\.([0-9]+)['"]/ + + def self.check? + !FILE.nil? + end + + private + + def read + file_version = File.open(FILE, 'r') { |f| f.grep(REGEX).first } + self.version = file_version + end + + def write + content = File.read(FILE).gsub(REGEX, "VERSION = '#{version}'") + File.open(FILE, 'w') { |f| f.write content } + end + end + + class Yaml < Version + FILE = File.join('config', 'version.yml') + + def self.check? + File.exist?(FILE) + end + + private + + def read + yaml = YAML.load_file(FILE) + + self.major = yaml['major'].to_i + self.minor = yaml['minor'].to_i + self.patch = yaml['patch'].to_i + end + + def write + File.open(FILE, 'w') do |f| + f.write YAML.dump('major' => major, 'minor' => minor, 'patch' => patch) + end + end + end + end + + class Git + REMOTE = 'origin' + RELEASE_BRANCH = 'master' + + def self.create + develop_branch = current_branch + + Cocaine::CommandLine.new('git', 'fetch :remote').run(remote: REMOTE) + + stash = Cocaine::CommandLine.new('git', 'stash create').run.chomp + Cocaine::CommandLine.new('git', 'reset --hard').run + + Cocaine::CommandLine.new('git', 'checkout :branch').run(branch: RELEASE_BRANCH) + Cocaine::CommandLine.new('git', 'merge --ff-only :branch').run( + branch: "#{REMOTE}/#{RELEASE_BRANCH}") + + Cocaine::CommandLine.new('git', 'checkout :branch').run(branch: develop_branch) + + version = Version.load + version.increment + + version.save + + Cocaine::CommandLine.new('git', 'add :file').run(file: version.file) + Cocaine::CommandLine.new('git', 'commit -m :message').run( + message: "Bump version to #{version.version}") + + Cocaine::CommandLine.new('git', 'checkout :branch').run(branch: RELEASE_BRANCH) + Cocaine::CommandLine.new('git', 'merge --no-ff -m :message :branch').run( + message: "Merge release #{version.version}", branch: develop_branch) + + Cocaine::CommandLine.new('git', 'tag -a -m :message :tag').run( + message: "Release #{version.version}", tag: version.version) + ensure + Cocaine::CommandLine.new('git', 'checkout :branch').run(branch: develop_branch) + Cocaine::CommandLine.new('git', 'stash apply :stash').run(stash: stash) unless stash.to_s.empty? + end + + def self.current_branch + branch = Cocaine::CommandLine.new('git', 'rev-parse --abbrev-ref HEAD').run.chomp + branch == 'HEAD' ? current_commit : branch + end + + def self.current_commit + Cocaine::CommandLine.new('git', 'rev-parse HEAD').run.chomp + end + end +end + +Release::Git.create diff --git a/bin/pipes.sh b/bin/pipes.sh new file mode 100755 index 0000000..949e43f --- /dev/null +++ b/bin/pipes.sh @@ -0,0 +1,108 @@ +#!/bin/bash +# The author of the original script is unknown to me. The first entry I can +# find was posted at 2010-03-21 09:50:09 on Arch Linux Forums (doesn't mean the +# poster is the author at all): +# +# https://bbs.archlinux.org/viewtopic.php?pid=728932#p728932 +# +# I, Yu-Jie Lin, made a few changes and additions: +# +# -p, -t, -R, and -C +# +# Screenshot: http://flic.kr/p/dRnLVj +# Screencast: http://youtu.be/5XnGSFg_gTk +# +# And push the commits to Gist: +# +# https://gist.github.com/4689307 +# +# I, Devin Samarin, made a few changes and additions: +# +# -r can be 0 to mean "no limit". +# Reset cursor visibility after done. +# Cleanup for those people who want to quit with ^C +# +# Pushed the changes to https://gist.github.com/4725048 + +p=1 +f=75 s=13 r=2000 t=0 +w=$(tput cols) h=$(tput lines) +# ab -> idx = a*4 + b +# 0: up, 1: right, 2: down, 3: left +# 00 means going up , then going up -> ┃ +# 12 means going right, then going down -> ┓ +sets=( + "┃┏ ┓┛━┓ ┗┃┛┗ ┏━" + "│╭ ╮╯─╮ ╰│╯╰ ╭─" + "│┌ ┐┘─┐ └│┘└ ┌─" + "║╔ ╗╝═╗ ╚║╝╚ ╔═" +) +v="${sets[0]}" +RNDSTART=0 +NOCOLOR=0 + +OPTIND=1 +while getopts "p:t:f:s:r:RCh" arg; do +case $arg in + p) ((p=(OPTARG>0)?OPTARG:p));; + t) ((OPTARG>=0 && OPTARG<${#sets[@]})) && v="${sets[OPTARG]}";; + f) ((f=(OPTARG>19 && OPTARG<101)?OPTARG:f));; + s) ((s=(OPTARG>4 && OPTARG<16 )?OPTARG:s));; + r) ((r=(OPTARG>=0)?OPTARG:r));; + R) RNDSTART=1;; + C) NOCOLOR=1;; + h) echo -e "Usage: $(basename $0) [OPTION]..." + echo -e "Animated pipes terminal screensaver.\n" + echo -e " -p [1-]\tnumber of pipes (D=1)." + echo -e " -t [0-$((${#sets[@]} - 1))]\ttype of pipes (D=0)." + echo -e " -f [20-100]\tframerate (D=75)." + echo -e " -s [5-15]\tprobability of a straight fitting (D=13)." + echo -e " -r LIMIT\treset after x characters, 0 if no limit (D=2000)." + echo -e " -R \t\trandom starting point." + echo -e " -C \t\tno color." + echo -e " -h\t\thelp (this screen).\n" + exit 0;; + esac +done + +cleanup() { + tput rmcup + tput cnorm + exit 0 +} +trap cleanup SIGHUP SIGINT SIGTERM + +for (( i=1; i<=p; i++ )); do + c[i]=$((i%8)) n[i]=0 l[i]=0 + ((x[i]=RNDSTART==1?RANDOM*w/32768:w/2)) + ((y[i]=RNDSTART==1?RANDOM*h/32768:h/2)) +done + +tput smcup +tput reset +tput civis +while ! read -t0.0$((1000/f)) -n1; do + for (( i=1; i<=p; i++ )); do + # New position: + ((${l[i]}%2)) && ((x[i]+=-${l[i]}+2,1)) || ((y[i]+=${l[i]}-1)) + + # Loop on edges (change color on loop): + ((${x[i]}>w||${x[i]}<0||${y[i]}>h||${y[i]}<0)) && ((c[i]=RANDOM%8)) + ((x[i]=(x[i]+w)%w)) + ((y[i]=(y[i]+h)%h)) + + # New random direction: + ((n[i]=RANDOM%s-1)) + ((n[i]=(${n[i]}>1||${n[i]}==0)?${l[i]}:${l[i]}+${n[i]})) + ((n[i]=(${n[i]}<0)?3:${n[i]}%4)) + + # Print: + tput cup ${y[i]} ${x[i]} + [[ $NOCOLOR == 0 ]] && echo -ne "\033[1;3${c[i]}m" + echo -n "${v:l[i]*4+n[i]:1}" + l[i]=${n[i]} + done + ((r>0 && t*p>=r)) && tput reset && tput civis && t=0 || ((t++)) +done + +cleanup