Hobby-hacking Eric

Showing posts with label mac. Show all posts
Showing posts with label mac. Show all posts

2010-12-02

personal gitit wiki on MacOS X

Here's a quick little recipe for using gitit as a personal wiki on MacOS X. I assume here you already have the wiki itself set up, and now you just want it to run automatically in the background whenever you log in. You can do this by using launchd.
  1. Download net.johnmacfarlane.gitit.plist from this Gist
  2. Replace the WorkingDirectory with the path to your personal wiki
  3. Replace the last part of the PATH to include your cabal directory, and possibly something like /usr/local/bin or /opt/local/bin if you're using Git instead of Darcs
  4. Save the file in ~/Library/LaunchAgents
  5. Test it with launchctl load ~/Library/LaunchAgents, maybe using the Console application to search for logs should something go wrong.
  6. Log out and log back in (or maybe even restart your computer if you want to be sure)
Helpful bits and pieces:
  • This MacGeekery article
  • launchd.plist man page
  • Property List Editor in Developer Tools (beats looking at XML)
Edit 2010-12-04: Fixed broken link


2009-09-11

cabal installing graphical apps on MacOS X

I have a graphical command line tool written in wxHaskell. For the longest time, my tool was relatively easy to install on Linux but a pain on MacOS X because my users had to jump through extra post-installation hoops like creating application bundles.

Thanks to some very patient help from Beelsebob, quicksilver, dcoutts on #haskell I was finally able to cobble together a Setup.hs file that lets me do just this. Now when I write install instructions for my program, I no longer need to add extra bullet points telling people to turn knobs and twiggle blops just to run the GUI. It just works.

Note that this was written with wxHaskell in mind. I hope that folks using gtk2hs and qtHaskell either do not have this problem or can make use of a similar solution.

desiderata

What I wanted was for the 'cabal install' command to work as well on MacOS X as it did under Linux. My core desiderata were:
  1. Ability to call my application from the command line the same way you would under Linux with command line arguments correctly recognised
  2. No need for the user to add extra junk to the path (besides $HOME/.cabal/bin which they'll already have added)
  3. No manual intervention after cabal install (eg calling scripts to create application bundles)
  4. No need to be super-user.


basic ideas

The basic ideas behind this solution are
  • Replace "foo" with a shell script that calls "foo.app/MacOS/Contents/foo"
    MacOS X Leopard seems to want graphical applications to live in application bundles. At least for wxHaskell if you invoke "foo" you get a GUI that does not respond to input. On the other hand, if you invoke "foo.app/MacOS/Contents/foo" you get something that works.
  • Use a Cabal postInst to create the application bundle in the bin dir.

basic solution

Here is the solution. (I'll send it as a mail to the wxhaskell-users mailing list too)
-- --------------- BEGIN Setup.hs EXAMPLE ------------------------------
import Control.Monad (foldM_, forM_)
import Data.Maybe ( fromMaybe )
import System.Cmd
import System.Exit
import System.Info (os)
import System.FilePath
import System.Directory ( doesFileExist, copyFile, removeFile, createDirectoryIfMissing )

import Distribution.PackageDescription
import Distribution.Simple.Setup
import Distribution.Simple
import Distribution.Simple.LocalBuildInfo

main :: IO ()
main = defaultMainWithHooks $ addMacHook simpleUserHooks
where
addMacHook h =
case os of
"darwin" -> h { postInst = appBundleHook } -- is it OK to treat darwin as synonymous with MacOS X?
_ -> h

appBundleHook :: Args -> InstallFlags -> PackageDescription -> LocalBuildInfo -> IO ()
appBundleHook _ _ pkg localb =
forM_ exes $ \app ->
do createAppBundle theBindir (buildDir localb </> app </> app)
customiseAppBundle (appBundlePath theBindir app) app
`catch` \err -> putStrLn $ "Warning: could not customise bundle for " ++ app ++ ": " ++ show err
removeFile (theBindir </> app)
createAppBundleWrapper theBindir app
where
theBindir = bindir $ absoluteInstallDirs pkg localb NoCopyDest
exes = fromMaybe (map exeName $ executables pkg) mRestrictTo

-- ----------------------------------------------------------------------
-- helper code for application bundles
-- ----------------------------------------------------------------------

-- | 'createAppBundle' @d p@ - creates an application bundle in @d@
-- for program @p@, assuming that @d@ already exists and is a directory.
-- Note that only the filename part of @p@ is used.
createAppBundle :: FilePath -> FilePath -> IO ()
createAppBundle dir p =
do createDirectoryIfMissing False $ bundle
createDirectoryIfMissing True $ bundleBin
createDirectoryIfMissing True $ bundleRsrc
copyFile p (bundleBin </> takeFileName p)
where
bundle = appBundlePath dir p
bundleBin = bundle </> "Contents/MacOS"
bundleRsrc = bundle </> "Contents/Resources"

-- | 'createAppBundleWrapper' @d p@ - creates a script in @d@ that calls
-- @p@ from the application bundle @d </> takeFileName p <.> "app"@
createAppBundleWrapper :: FilePath -> FilePath -> IO ()
createAppBundleWrapper bindir p =
writeFile (bindir </> takeFileName p) scriptTxt
where
scriptTxt = "`dirname $0`" </> appBundlePath "." p </> "Contents/MacOS" </> takeFileName p ++ " \"$@\""

appBundlePath :: FilePath -> FilePath -> FilePath
appBundlePath dir p = dir </> takeFileName p <.> "app"

-- optional stupff: to be discussed later
mRestrictTo = Nothing
customiseAppBundle _ _ = return ()
-- --------------- END Setup.hs EXAMPLE ---------------------------------

fancier solution


I also have some extra wishlist items.
  1. Possibility of installing in --global
  2. Fancy custom app bundles with custom icons and what not

Global installation might already be working with this basic script, but I haven't tested it yet. Fancy app bundles sort of work (if I double-click it in Finder, I get a customised icon, but running it from the command line does not give me one).

Here are extra hooks I created for this:
-- ------------- BEGIN FANCY Setup.hs ADDENDUM ------------------------
-- | Put here IO actions needed to add any fancy things (eg icons)
-- you want to your application bundle.
customiseAppBundle :: FilePath -- ^ app bundle path
-> FilePath -- ^ full path to original binary
-> IO ()
customiseAppBundle bundleDir p =
case takeFileName p of
"geni" ->
do hasRez <- doesFileExist "/Developer/Tools/Rez"
if hasRez
then do -- set the icon
copyFile "etc/macstuff/Info.plist" (bundleDir </> "Contents/Info.plist")
copyFile "etc/macstuff/wxmac.icns" (bundleDir </> "Contents/Resources/wxmac.icns")
-- no idea what this does
system ("/Developer/Tools/Rez -t APPL Carbon.r -o " ++ bundleDir </> "Contents/MacOS/geni")
writeFile (bundleDir </> "PkgInfo") "APPL????"
-- tell Finder about the icon
system ("/Developer/Tools/SetFile -a C " ++ bundleDir </> "Contents")
return ()
else putStrLn "Developer Tools not found. Too bad; no fancy icons for you."
"" -> return ()

-- | Put here the list of executables which contain a GUI. If they all
-- contain a GUI (or you don't really care that much), just put Nothing
mRestrictTo :: Maybe [String]
mRestrictTo = Just ["geni"]
-- ------------- END FANCY Setup.hs ADDENDUM ---------------------------


2007-01-16

House runs under Parallels

House is an operating system written in Haskell. Ever since CSE380 (titled "Operating Systems") and my many many segfaults, I have deeply impressed with those I call "people who know how computers work". So whenever somebody says "I wrote an operating system!"... I simply marvel.

Anyway, was just sort of fiddling with my computer trying to see if I can get it to run, but I was having the toughest time! The thing boots fine under Q (the qemu front end), but nothing I did could make it work on Parallels. Tried renaming it with .hdd extension, but then I just got a grub prompt with no idea how to proceed. Renaming it to .fdd and connecting it as a floppy wouldn't work, so my first reaction was "oh! it must be some kind of crazy Parallels-specific format", so I kept searching the web and asking on IRC, trying to see if anyone know how to produce Parallels-compatible bootable floppy images...

Well you know what the problem was?

Next to the floppy drive icon [connected to hOp-0.8.fdd] are two checkboxes, Enabled and Connect on Startup. Connect on Startup was unchecked.

Yes eric, you have to put the disk in the drive for it to work... good job!

What a dolt.

Edit 2006-01-17

Here are a couple of screenshots, as requested. The first is just the Parallels window:


And the second is of the whole desktop (probably a little gratuitous):


If you're having trouble getting this to work on your machine:
  1. Rename hOp-0.8.flp to hOp-0.8.fdd
  2. Add it as the floppy disk drive to your virtual machine
  3. Set the boot sequence to start with the floppy (or at least, have the floppy somewhere)
  4. Remember to click that Connect on Setup button next to the floppy config


Parallels might crash the first two times you do this. I have no idea why, but it seems to work after that.