Monday, January 12, 2009

Finding writable files in a directory in a windows command line

Simple thing, but if you want to find which files in a directory are writable, use this dos command ...


dir /a-r-d /s /b


/a is to search for attributes. In this case r is read only and d is directory. The minus signs negate those attributes. So we're looking for writable files only.

/s means recurse subdirectories

/b means bare format. Path and filename only.

Thursday, January 8, 2009

Who changed the line your working on last?

My team use Perforce for version control, and I recently wrote an implementation of 'blame', also known as 'praise'. When editing a file that is in Perforce, I can run p4-blame, and it will figure out the last change list that this file, and the line that point is on, was changed. It then opens a buffer containing that change list. This is often useful while working, and is so fast when accessed from the editor, it makes it trivial to do.

First, I wanted it to open two buffers, one with the annotated file (the file you're working on with the change list number at the start of each line), and another with the changelist you're interested in. When running the command multiple times I want these buffers to be deleted. So I added a helper function that creates a named buffer, and if it exists already, makes sure it is empty.


(defun get-buffer-create-and-clear(name)
(interactive "sName: ")
(let ((buffer (get-buffer-create name)))
(goto-line 1 buffer)
(erase-buffer)
buffer))


Ok now for the blame code. As you can see, mostly what it's doing is called the P4 command line and passing the output to buffers. Firstly I call annotate to get the change list numbered lines. Then I go to that file and go to the same line that point was at. (number-at-point) returns that number. Finally I call p4 describe to get the changelist information.


(defun p4-blame()
"blame the current line of code... it seeks out the change list of the last person
to change this line. The arguments to annotate, which dumps the source file with the
change list number it was last altered in, are q (no header) i (follow branches) and
c for change numbers rather than revision numbers."
(interactive)
(let* ((line (line-number-at-pos))
(source-file (buffer-file-name))
(annotate-buffer (get-buffer-create-and-clear "*p4-annotate*")))
(shell-command (format "p4.exe annotate -q -i -c %s" source-file) annotate-buffer)
(goto-line line annotate-buffer)
(let ((change-number (number-at-point)))
(if change-number
(let ((blame-buffer (get-buffer-create-and-clear "*p4-blame*")))
(shell-command (format "p4.exe describe %d" change-number) blame-buffer))
(message "error: could not get change list number for line %d" line)))))



The error detection is a bit sloppy here. I don't know how to figure out if the shell-command failed. But it's not a big deal because if you do this in a file that is not in P4 then it will simply print a message saying could not get change list.

Ideally I could send the error output to a buffer, and then parse it to see if it's empty.

Friday, November 21, 2008

How to copy an SVN repository from sourceforge to google code

Subversion has a tool called SVNSYNC  to make it easy to sync from one repository to another. This is great when moving to a different web based server. In this example I'm copying a project I work on from Sourceforge to Google Code. Once done, the google code repository will be an exact mirror, including the complete change history.

You also need to set the revision number of the repository to zero. Google code, predictably, makes this easy, by having a button on the source page to do it for you.

You need to have your username and password for google code to do this. For the repository you're copying you don't. First you use the initial command to set things up for the copy, then use the sync command to do the actual copy. It does this one revision at a time and takes a while...


svnsync init https://lispbuilder.googlecode.com/svn https://lispbuilder.svn.sourceforge.net/svnroot/lispbuilderProject
svnsync --username YOURNAME --password YOURPASSWORD sync https://lispbuilder.googlecode.com/svn https://lispbuilder.svn.sourceforge.net/svnroot/lispbuilder

Saturday, November 8, 2008

Grabbing info from web pages

This is how you use wget to grab a web page to stdout ...

wget -O - http://newsrss.bbc.co.uk/rss/newsonline_world_edition/front_page/rss.xml

Where -O species the output file, and the - specifies use stdout instead of a filename.

Tuesday, May 27, 2008

Using find and printf

This is basic stuff but I wanted to post it so I can find it when I search for it...

How to find a file and print the name, path and date and time it was last accessed...

Change filename to be the file you want, with optional wildcards. (Use -iname for case insensitive search).


find . -name -printf "%p %AD %AH:%AM\n"

Tuesday, May 13, 2008

Batch file tip ... %~dp0

Here's a nice blog post on this...

Silly batch file tricks, redirecting stdout into an evironment variable and %~dp0

But just for my own reference the cryptic looking character sequence resolves to the path to the batchfile you are running.

So if you put the following in a batch file, no matter what directory you are in when you run it, it will print the directory the batch file is in, and do a directory listing.


echo Batch file path is %~dp0
dir %~dp0

Thursday, May 1, 2008

Copying characters from the line above in emacs

The BBC microcomputer had a button called COPY, which when you pressed it would copy the character on the line above the cursor. This was quite handy, and I recently was waiting for a large amount of code to link, and thought I'd have a go at implementing it.

There's not a lot to it in fact. This function just remembers the cursor position (using save-excursion) and then goes to the previous line, gets the character after the point, and finally after the save-excursion block I just insert the character.


(defun copy-char-above()
"copy the character above point into the buffer"
(interactive)
(let (c)
(save-excursion
(previous-line)
(setq c (char-after)))
(insert (char-to-string c))))


Here I just assign the function to a key...


(global-set-key [f6] 'copy-char-above)