Search My Blog

ruby (4) web (4) ruby on rails (3) security (3) GPG (2) OpenPGP (2) RFC (2) linux (2) rails (2) shell (2) sysadmin (2) Exchange (1) GIT. (1) IMAP (1) RCS (1) SSH (1) SVN (1) bundle (1) cURL (1) command line (1) crack (1) css (1) developer (1) email (1) fail (1) hack (1) http (1) mac (1) network (1) password (1) regular expression (1) script (1) subversion (1) terminal (1) textmate (1) tip (1) vim (1)
Showing posts with label linux. Show all posts
Showing posts with label linux. Show all posts

Friday, January 27, 2012

How to put any directory under SVN revision control using a self-contained repository

Okay, I've not found this elsewhere so I'm writing a post about how I did it.
The tipical SVN scenario is when you and other people are working on shared files by checking out any number of working copies from a repository,
$ svn checkout http://svn.collab.net/repos/svn/trunk /home/me/src/project4/working_copy3
modifying the files and then committing the changes and let the revision control system manage conflicts and merge the updates.
$ svn commit -m "Corrected number of cheese slices."
In this scenario the best place for the repository is in a dedicated and secured server, it doesn't make any sense to have the repository inside its working copy: you want to feel free to make any kind of disaster and even delete the whole directory because you know you can start all over again by checking out a fresh original copy.

But SVN is so simple and powerful that you can let it track any changes that happens on a directory on your own personal computer, for backup or security purposes (think about /etc) or to study what an application does to the the files; and sometimes it may be convenient to create the repository in the same directory that repository is controlling, so you can always backup and move the directory without worrying to break the relationship between the working copy and the repository.
In my case I had an encrypted volume that I mount and unmount in different computers and I wanted to track the changes on this volume even without a network connection, so it turned out that making a self-contained SVN system was the best choice.

There are some simple initial steps to do this, and once completed you can work on the directory as you do usually with any other working copy. Before proceeding just make sure to make a backup of anything you are touching.


Suppose "/pwd" is the directory you want to put under revision control, and start creating a SVN repository where you want (since it will be moved later, I'll place it under /tmp):
$ svnadmin create /tmp/repo/
then import /pwd in this repository and remove it if successfully imported:
$ svn import /pwd/ file:///tmp/repo/ -m '[/] Start tracking all changes within pwd' && rm -fr /pwd/
Now if you check it out you'll have just put /pwd under revision control:
$ svn checkout file:///tmp/repo/ /pwd/

...but wait! IT'S NOT THAT SIMPLE FOR "LIVE" DIRECTORIES!
If you are working on a "live" directory (such as /etc on a busy system), it's not very safe to simply import and delete it because some files may need to change before you check out. So on a "live" directory we'll do it slightly differently:
$ svnadmin create /tmp/repo/
$ svn import /pwd/ file:///tmp/repo/ -m '[/] Start tracking all changes within pwd'
we'll check out under another temporary path
$ svn checkout file:///tmp/repo/ /tmp/pwd/
and move just the SVN system folders into the "live directory":
$ find /tmp/pwd/ -type d -name ".svn" -exec mv -vi {} /pwd/ \;
NOTE: In a Mac OS environment, use 'ditto' instead of 'mv':
$ cd /tmp/pwd/
$ find . -d -type d -name ".svn" -exec ditto {} /pwd/{} \;
$ cd ~-
Now /pwd is effectively a working copy and you can update the files that changed in the meanwhile, and get rid off the other working copy /tmp/pwd:
$ rm -fr /tmp/pwd/

And here comes the part to move the repository inside the working copy:
Change to /pwd/ and update (only needed if it was a "live" directory)
$ cd /pwd/ && svn update
tell SVN to ignore the folder ".repo" where we will put the repository, and commit.
$ svn propset svn:ignore .repo .
$ svn commit -m '[/] svn propset svn:ignore .repo .'
At this point, instead of just moving the repository in "/pwd/.repo", we make a precautionary step to ensure that if we are working on a "live" directory no changes would be lost when we relocate the repository: first we symlink the repository,
$ ln -s /tmp/repo/ .repo
then we tell what is the new location of the SVN repository
$ svn switch --relocate file:///tmp/repo/ file:///pwd/.repo/
and only after making the switch we effectively move it replacing the symlink all at once
$ rm /pwd/.repo && mv -vf /tmp/repo/ /pwd/.repo/
Now you have a self-contained revision control of the current directory.



If you find this useful please leave a comment ;)

Thursday, October 6, 2011

Add a shortcut to TextMate to lookup a class or method definition in a tooltip

UPDATED Mar 11 Ott 2011 12:52:36 CEST

I'm Vim user. I love the command mode, and I had fun to dance with those keystroke commands.
However changing OS means viewing things in another perspective, and switching from Linux to Mac OS for me meant choosing an editor that has its roots in the operating system where it runs.
In the case of Mac OS it not only means it should have a suitable GUI, but it should fire up instantly and above all it should behave like a Mac App.
TextMate was the obvious choice. Because behaving like a Mac App means that if you pick a folder in the Finder and drop it in the editor icon, it should straight open it like a Project. And it means that under the guise of a bare and simple application hides a world of possibilities and customization. That world in TextMate is called Bundles.

Let's talk about Bundles with a real case. (TextMate|I) was missing a shortcut to quickly lookup the definition of a class or method name, so I decided to write a TextMate command that shows me the definition in a tooltip for the current word under the caret.
The difficulties I had were merely related to the complexity of this shell scripting. Since I was trying to keep it as simple and efficient I could, I chose to use the standard unix tools: grep find and sed (it ended up that maybe a ruby script would have done it easier :))

All you have to do to use it in your TextMate is to open the Bundle editor (⌃ ⌥ ⌘ B), make a new command under "Ruby", assign a "Key Equivalent" like ⌃ ] and paste the following script in the "Command(s):" windows
#!/bin/bash
SEARCHPATH=$(test -x "$TM_PROJECT_DIRECTORY" && echo "$TM_PROJECT_DIRECTORY" || echo $(dirname "$TM_FILEPATH") )
STARTPATTERN="^([[:space:]]|;)*(def|class)([[:space:]]|;)+$TM_CURRENT_WORD([^A-Za-z0-9_].*)*$"
ENDPATTERN="^([[:space:]]|;)*end([[:space:]]|;)*"
FILESMATCH=$( (egrep -ns "$STARTPATTERN" "$TM_FILEPATH" || egrep -nsR "$STARTPATTERN" --exclude="*.svn*" "$SEARCHPATH") |cut -d: -f-2 )
echo $FILESMATCH # Show on tooltip
echo $FILESMATCH |cut -d: -f1 |xargs -0 basename |pbcopy # Copy on clipboard for later use with cmd+T
find "$TM_FILEPATH" "$SEARCHPATH" -type f -name '*.rb' -exec sed -En "/$STARTPATTERN/,/$ENDPATTERN/p" {} \; |sed -E "/$ENDPATTERN/q"
CODE UPDATED Mar 11 Ott 2011 12:52:36 CEST
Now it also copies the first matching filename to the clipboard, so you can open this file by pressing cmd+T (and then go to the exact line with cmd+L)

Make sure the output is "Show as Tool Tip" like this:

If you've done it correctly, placing the caret on or after any method or class name and pressing ⌃ ] (or whatever key assignment you've made) will search in the current file ($TM_FILEPATH) and then recursively in the project directory ($TM_PROJECT_DIRECTORY) or in the file directory (if file is not in a project), and show a tooltip with:
  1. the name of the file (if different from the one you are editing) and the line where the first definition of the method or class is found
  2. the portion of definition from the declaration to the first "end" found

Although not perfect, it will do its best to avoid commented lines and false matches.
Even if this script was done for ruby, you can use it as a base for other programming languages, just change the -name '*.rb' part of the find command in the extension of your sources, and the keywords def - class - end that matches your method, function or class definitions.

In the very unsual case you are running TextMate not on a Mac OS, or if you want to adapt the script to run in a linux shell, just skip the line to "Copy on clipboard for later use with cmd+T" and remember that to use the Extended Regular Expression in SED you have to use the -r switch instead of -E.

For any explanation, contribution or discussion on the script please leave a comment below, and if you find it useful please leave me a positive feedback! :)