Thursday, February 23, 2012

Working with ssh-agent

For checking some git repositories it is very uncomfortable to work with public-keys because you have to commit the key every time you want to push, pull or other communications with the git repository.

If you have a lot of git repositories for a project you have to change to the first directory, make a git pull, commit your password for the public key and go to the next directory. For a lot of directories it is very bad style.

This is were ssh-agent comes to the spot. I start the ssh-agent and commit my password for the public key once with ssh-add. After that you can work with all git repositories were you have the same public key committed. The idea of the ssh-agent is to start it once and then you have to put some environment variables into all your shell where you are working. That's not very nice for me so I wrote a zsh-function for that case. Here you can see the function:
function ssha {
  if [ $# -ne 1 ]; then
    echo "usage: $0 [start|stop]"
    return 1
  fi
  case "$1" in
    start)
      if [ -n "$SSH_AGENT_PID" ]; then
        echo "ssh-agent already running"
        return 1
      fi
      /usr/bin/ssh-agent > /tmp/ssh-agent-pids
      . /tmp/ssh-agent-pids > /dev/null
      /usr/bin/ssh-add
      ;;
    stop)
      if [ -z "$SSH_AGENT_PID" ]; then
        echo "ssh-agent not running"
        return 1
      fi
      /usr/bin/ssh-agent -k > /tmp/ssh-agent-pids
      . /tmp/ssh-agent-pids > /dev/null
      ;;
    *)
      echo "usage: $0 [start|stop]"
      return 1
      ;;
  esac
}
You can start and stop the ssh-agent with the same function. If you are working with some git repositories you could start it with ssha start. Then you have to give your password for the public key and you can work in the same shell. After finishing some work with that git repositories you could stop the server with ssha stop.

Wednesday, February 22, 2012

Organizing my world with taskwarrior and org-mode

For organizing my world i use to tools. First taskwarrior for creating an working with tasks and emacs org-mode for writing documentation. I know there is a option to use org-mode for tasks too but this is not useful for my workflow. I prefere to use taskwarrior.

The only missing thing in taskwarrior ist that i cannot add some descriptions for a task. This is the point were org-mode comes into the spot. I wrote a litte script which creates a note for a task. I call this script taskcomment.

Here you can see the short version of the code:
FOLDER=${WIKI}/tasks/comments
UUID=`task rc._forcecolor=no rc.defaultwidth=300 $1 | \
      grep UUID | grep -o "[-a-f0-9]*\$"`
TITLE=`task $1 | grep Description | sed 's/^Description\ //g'`
FILE="${UUID}.org"

if [ ! -f ${FOLDER}/${FILE} ]; then
    echo "#Title: ${TITLE}" > ${FOLDER}/${FILE}
    echo "#+STARTUP: showall" >> ${FOLDER}/${FILE}
    /usr/bin/task append $1 '[c]'
fi

${EDITOR} ${FOLDER}/${FILE}
First I check the UUID for a given task. The script taskcomment will have an available ID of a task. The UUID will be produced by taswarrior for giving an unique identifier for all its tasks. I take this UUID and name my files in that case.

The second line shows how to I get the title of the task. The title is important for the closed tickets because taskwarrior rearranges its tasks already new after closing one ticket. So the closed tickets do not have an ID. This is a problem which I have to solve in the near future because if you have a closed ticket you have to activate it that it becomes a new ID and then can you work with it. After that you already have to close this ticket. That's very bad style.

Afterwards the script checks if the comment file is a new file or not. If it is a new file it will create some useful comments at the top of the file.

If you want to work with that script you could start it like:
$ taskcomment 5
Next the script adds a '[c]' to the description line of the task to show there is a comment attached to this task. I found it nicer to do it in that way because it is much nicer and compact instead working with annotations. Here you can see an output of the taskwarrior with my extensions:
% task 
[task list]

ID Project Pri Due       Active Age    Description                                                                 
11 test        24.2.2012        14 hrs Testentry
 3 test    M   11.3.2012        16 hrs Testentry with comment [c]   

The comment file will be opened in my case with Emacs in org-mode because I use the extension .org for opening files. That's the way I work with taskwarrior and Emacs in org-mode for organizing my world ;)

Wednesday, February 8, 2012

Scripting in Haskell and reading current playing song

If you use Xmonad as your prefered window manager you have to script some information for yourself. So I wanted to put my current playing song into the bottom bar.


On the image above you can see my bottom bar with the information of the current playing song. For this I use xmobar for putting this information into the bottom bar and mocp for getting the information which song is currently playing.

The nice thing is if you want to script with Haskell just put the following line to the first line of your script and you can run it after you give the appropriate permissions (chmod +x).
#!/usr/bin/env runhaskell
The following code will show you how to get a information from an external program and parse some important information and put it to stdout.
#!/usr/bin/env runhaskell

module Main where

import System.Process (readProcess)
import Data.List (isPrefixOf)

sizeOfString :: Int
sizeOfString = 47

split :: Eq a => a -> [a] -> [[a]]
split d = foldr f [[]]
  where f c l@(x:xs) | c == d = []:l
                     | otherwise = (c:x):xs

-- | my head function doesn't crash if there is an empty list                                                                                          
head' :: [String] -> String
head' [] = ""
head' (x:xs) = x

-- | my tail function doesn't chrash if there is an empty list                                                                                         
tail' :: [a] -> [a]
tail' [] = []
tail' (x:xs) = xs

line :: String -> IO [String]
line start = do
  s <- readProcess "mocp" ["-i"] []
  let t = split '\n' s
  let l = filter (isPrefixOf start) t
  return $ words $ head' l

reduceLine :: String -> String
reduceLine s
  | length s <= sizeOfString + 3 = s
  | otherwise = take sizeOfString s ++ "... "

main :: IO ()
main = do
  s <- line "SongTitle"
  a <- line "Artist"
  let song = foldr (++) "" $ map (++" ") $ tail' s
  let artist = foldr (++) "" $ map (++" ") $ tail' a
  if (length artist == 0)
    then if (length song == 0)
         then putStrLn $ "stop "
         else putStrLn $ reduceLine song
    else putStrLn $ reduceLine $ artist ++ ":: " ++ song
I know the code could be much shorter but its nice for learning Haskell and learn how to script with Haskell.

Tuesday, February 7, 2012

Open library files from /w ghci

If you want to get some information about a function in GHC just do
ghci> :t sum
sum :: Num a => [a] -> a -- Defined in Data.List
What do you do if you want to look at the source of that file just from /w the interpreter ghci? You could do following.

Download the source from ghci an put it wherever you want. For all Debianer out there just do following:
apt-get source ghc
After that you have to define a macro in ghci. You can also define this macro in the configuration file for ghci in $HOME/.ghc/ghci.conf.
:def source \s -> return $ ":! openGHCLib.sh " ++ s
Afterwards you have to write the script openGHCLib.sh and put it into your PATH. The script openGHCLib.sh look like:
#!/bin/bash

# path where you put the source files of ghc
base_path=$HOME/tmp/ghc-7.0.4/libraries/base
file=`echo $1 | tr '.' '/'`
hfile="${base_path}/${file}"

if [ -e "${hfile}.hs" ]; then
  ${EDITOR} "${hfile}.hs"
elif [ -e "${hfile}.lhs" ]; then
  ${EDITOR} "${hfile}.lhs"
else
  echo "file: ${hfile}.hs or ${hfile}.lhs does not exist"
  exit 1
fi
After that you can open the library file /w ghci.
ghci> :source Data.List