Thursday, December 20, 2012

Maven - Install missing offline dependencies automatically

Sometime it happens that we need to share with someone else part of a complex Java project based on Maven.
The project is probably composed of various modules, with their dependency relationships, but the different modules are also logically separated. So it make completely sense that we'd like to share only on those submodules.

To do that we have to modify the pom.xml and remove the <parent> section and probably also specify properties and dependencies version that are often defined in the super pom.
But with the help of Eclipse and its "Effective POM" view it's not that hard.

The real problem is that all those actions are not enough to have a portable project.
What is missing is the list of dependency defined in the submodules that we do not want to share as source code and that won't be available to be downloaded from Maven public repositories.

Since those artifacts are required to build the project, what we can do is to manually install them from the command line with the typical:

mvn install:install-file 
 -Dfile=my_module.jar 
 -DgroupId=my.private.project 
 -DartifactId=my_module 
 -Dversion=1.0.0 
 -Dpackaging=jar
It works but it contrasts with the idea that our Maven build should be able to do all is required to build our project.

I was looking for an alternative solution and I have found it in this post on Stackoverflow: http://stackoverflow.com/questions/1355548/maven-including-jar-not-found-in-public-repository

 Let me describe it and also offer a ready git repo for a rapid testing of it.

https://github.com/paoloantinori/maven_automated_artifacts_installation

The main idea is to use the exec-maven-plugin to automatically install the dependency for us, replicating the manual activity.
In this way we can script all the manual activities that we needed. To better distinguish between what are the external libraries and our project I suggest a multimodule project:

Parent
|
+---Dependency Project
|
+---Our Interesting Project
Nothing interesting in the parent pom.xml:

  pom
  Sample :: Multimodule
  
  
    main_project
    dependencies_project
  

Let's have a look at the Main Project pom.xml:
  
    
    
      com.example.giallone
      dependencies
      1.0.0
    
    
    
      com.example.giallone
      dep1
      1.0.0
    
    
      com.example.giallone
      dep2
      1.0.0
    
  
As you can see we are defining 2 different things:

Under "real dependencies" you see references to artifacts that the project needs but are not available in Maven Public Repositories.

While instead the first dependency is to trigger the installation of those missing jars, action performed by the other module of this multimodule project.

 If you try now to build only this module it will fail with the following output , since those missing dependencies have not been installed yet:


pantinor@pantinor main_project$ mvn clean install
/usr/lib/jvm/java
[INFO] Scanning for projects...
[INFO]                                                                         
[INFO] ------------------------------------------------------------------------
[INFO] Building Sample :: Main Project 1.0.0
[INFO] ------------------------------------------------------------------------
Downloading: http://repo.maven.apache.org/maven2/com/example/giallone/dependencies/1.0.0/dependencies-1.0.0.pom
[WARNING] The POM for com.example.giallone:dependencies:jar:1.0.0 is missing, no dependency information available
[WARNING] The POM for com.example.giallone:dep1:jar:1.0.0 is missing, no dependency information available
[WARNING] The POM for com.example.giallone:dep2:jar:1.0.0 is missing, no dependency information available
Downloading: http://repo.maven.apache.org/maven2/com/example/giallone/dependencies/1.0.0/dependencies-1.0.0.jar
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 1.166s
[INFO] Finished at: Thu Dec 20 13:02:20 GMT 2012
[INFO] Final Memory: 5M/148M
[INFO] ------------------------------------------------------------------------
[ERROR] Failed to execute goal on project rules: Could not resolve dependencies for project com.example.giallone:rules:jar:1.0.0: The following artifacts could not be resolved: com.example.giallone:dependencies:jar:1.0.0, com.example.giallone:dep1:jar:1.0.0, com.example.giallone:dep2:jar:1.0.0: Could not find artifact com.example.giallone:dependencies:jar:1.0.0 in central (http://repo.maven.apache.org/maven2) -> [Help 1]
[ERROR] 
[ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch.
[ERROR] Re-run Maven using the -X switch to enable full debug logging.
[ERROR] 
[ERROR] For more information about the errors and possible solutions, please read the following articles:
[ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/DependencyResolutionException


Let's now have a look at the other module, dependencies_project:
  
    
      
        org.codehaus.mojo
        exec-maven-plugin
        1.2.1
        false
        
          
            install-in-repo-dep1
            validate
            
              exec
            
            
              mvn
              
                install:install-file
                -Dfile=${basedir}/lib/dep1.jar
                -DgroupId=com.example.giallone
                -DartifactId=dep1
                -Dversion=1.0.0
                -Dpackaging=jar
              
            
          
          
            install-in-repo-dep2
            validate
            
              exec
            
            
              mvn
              
                install:install-file
                -Dfile=${basedir}/lib/dep2.jar
                -DgroupId=com.example.giallone
                -DartifactId=dep2
                -Dversion=1.0.0
                -Dpackaging=jar
              
            
          
        
      
    
  
What we are doing here is to use exec-maven-plugin to install for us the missing dependencies in the local repo.
Those are the dependencies that prevent our main project to build successfully.

Having configured our main project to be dependent on this one, if we now build our project at the multimodule level, we will be able to trigger the 2 module in the right order:

[INFO] Reactor Build Order:
[INFO] 
[INFO] Sample :: Multimodule
[INFO] Sample :: Dependencies
[INFO] Sample :: Main Project


And when Multimodule Project is built, all the external dependencies are already installed in the previous step, allowing us to see a successful build! 

pantinor@pantinor install_artifacts_sample$ mvn clean install
/usr/lib/jvm/java
[INFO] Scanning for projects...
[INFO] ------------------------------------------------------------------------
[INFO] Reactor Build Order:
[INFO] 
[INFO] Sample :: Multimodule
[INFO] Sample :: Dependencies
[INFO] Sample :: Main Project
[INFO]                                                                         
[INFO] ------------------------------------------------------------------------
[INFO] Building Sample :: Multimodule 1.0.0
[INFO] ------------------------------------------------------------------------
[INFO] 
[INFO] --- maven-clean-plugin:2.4.1:clean (default-clean) @ common ---
[INFO] 
[INFO] --- maven-install-plugin:2.3.1:install (default-install) @ common ---
[INFO] Installing /data/repositories/github/install_artifacts_sample/pom.xml to /home/pantinor/.m2/repository/com/example/giallone/common/1.0.0/common-1.0.0.pom
[INFO]                                                                         
[INFO] ------------------------------------------------------------------------
[INFO] Building Sample :: Dependencies 1.0.0
[INFO] ------------------------------------------------------------------------
[INFO] 
[INFO] --- maven-clean-plugin:2.4.1:clean (default-clean) @ dependencies ---
[INFO] Deleting /data/repositories/github/install_artifacts_sample/dependencies_project/target
[INFO] 
[INFO] --- exec-maven-plugin:1.2.1:exec (install-in-repo-dep1) @ dependencies ---
/usr/lib/jvm/java
[INFO] Scanning for projects...
[INFO]                                                                         
[INFO] ------------------------------------------------------------------------
[INFO] Building Sample :: Dependencies 1.0.0
[INFO] ------------------------------------------------------------------------
[INFO] 
[INFO] --- maven-install-plugin:2.3.1:install-file (default-cli) @ dependencies ---
[INFO] Installing /data/repositories/github/install_artifacts_sample/dependencies_project/lib/dep1.jar to /home/pantinor/.m2/repository/com/example/giallone/dep1/1.0.0/dep1-1.0.0.jar
[INFO] Installing /tmp/mvninstall204045843544074291.pom to /home/pantinor/.m2/repository/com/example/giallone/dep1/1.0.0/dep1-1.0.0.pom
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 0.782s
[INFO] Finished at: Thu Dec 20 13:06:58 GMT 2012
[INFO] Final Memory: 4M/117M
[INFO] ------------------------------------------------------------------------
[INFO] 
[INFO] --- exec-maven-plugin:1.2.1:exec (install-in-repo-dep2) @ dependencies ---
/usr/lib/jvm/java
[INFO] Scanning for projects...
[INFO]                                                                         
[INFO] ------------------------------------------------------------------------
[INFO] Building Sample :: Dependencies 1.0.0
[INFO] ------------------------------------------------------------------------
[INFO] 
[INFO] --- maven-install-plugin:2.3.1:install-file (default-cli) @ dependencies ---
[INFO] Installing /data/repositories/github/install_artifacts_sample/dependencies_project/lib/dep2.jar to /home/pantinor/.m2/repository/com/example/giallone/dep2/1.0.0/dep2-1.0.0.jar
[INFO] Installing /tmp/mvninstall3544830050220263281.pom to /home/pantinor/.m2/repository/com/example/giallone/dep2/1.0.0/dep2-1.0.0.pom
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 1.116s
[INFO] Finished at: Thu Dec 20 13:07:01 GMT 2012
[INFO] Final Memory: 5M/148M
[INFO] ------------------------------------------------------------------------
[INFO] 
[INFO] --- maven-resources-plugin:2.5:resources (default-resources) @ dependencies ---
[debug] execute contextualize
[WARNING] Using platform encoding (UTF-8 actually) to copy filtered resources, i.e. build is platform dependent!
[INFO] skip non existing resourceDirectory /data/repositories/github/install_artifacts_sample/dependencies_project/src/main/resources
[INFO] 
[INFO] --- maven-compiler-plugin:2.3.2:compile (default-compile) @ dependencies ---
[INFO] No sources to compile
[INFO] 
[INFO] --- maven-resources-plugin:2.5:testResources (default-testResources) @ dependencies ---
[debug] execute contextualize
[WARNING] Using platform encoding (UTF-8 actually) to copy filtered resources, i.e. build is platform dependent!
[INFO] skip non existing resourceDirectory /data/repositories/github/install_artifacts_sample/dependencies_project/src/test/resources
[INFO] 
[INFO] --- maven-compiler-plugin:2.3.2:testCompile (default-testCompile) @ dependencies ---
[INFO] No sources to compile
[INFO] 
[INFO] --- maven-surefire-plugin:2.10:test (default-test) @ dependencies ---
[INFO] No tests to run.
[INFO] Surefire report directory: /data/repositories/github/install_artifacts_sample/dependencies_project/target/surefire-reports

-------------------------------------------------------
 T E S T S
-------------------------------------------------------

Results :

Tests run: 0, Failures: 0, Errors: 0, Skipped: 0

[INFO] 
[INFO] --- maven-jar-plugin:2.3.2:jar (default-jar) @ dependencies ---
[WARNING] JAR will be empty - no content was marked for inclusion!
[INFO] Building jar: /data/repositories/github/install_artifacts_sample/dependencies_project/target/dependencies-1.0.0.jar
[INFO] 
[INFO] --- maven-install-plugin:2.3.1:install (default-install) @ dependencies ---
[INFO] Installing /data/repositories/github/install_artifacts_sample/dependencies_project/target/dependencies-1.0.0.jar to /home/pantinor/.m2/repository/com/example/giallone/dependencies/1.0.0/dependencies-1.0.0.jar
[INFO] Installing /data/repositories/github/install_artifacts_sample/dependencies_project/pom.xml to /home/pantinor/.m2/repository/com/example/giallone/dependencies/1.0.0/dependencies-1.0.0.pom
[INFO]                                                                         
[INFO] ------------------------------------------------------------------------
[INFO] Building Sample :: Main Project 1.0.0
[INFO] ------------------------------------------------------------------------
[INFO] 
[INFO] --- maven-clean-plugin:2.4.1:clean (default-clean) @ rules ---
[INFO] Deleting /data/repositories/github/install_artifacts_sample/main_project/target
[INFO] 
[INFO] --- maven-resources-plugin:2.5:resources (default-resources) @ rules ---
[debug] execute contextualize
[WARNING] Using platform encoding (UTF-8 actually) to copy filtered resources, i.e. build is platform dependent!
[INFO] skip non existing resourceDirectory /data/repositories/github/install_artifacts_sample/main_project/src/main/resources
[INFO] 
[INFO] --- maven-compiler-plugin:2.3.2:compile (default-compile) @ rules ---
[INFO] No sources to compile
[INFO] 
[INFO] --- maven-resources-plugin:2.5:testResources (default-testResources) @ rules ---
[debug] execute contextualize
[WARNING] Using platform encoding (UTF-8 actually) to copy filtered resources, i.e. build is platform dependent!
[INFO] skip non existing resourceDirectory /data/repositories/github/install_artifacts_sample/main_project/src/test/resources
[INFO] 
[INFO] --- maven-compiler-plugin:2.3.2:testCompile (default-testCompile) @ rules ---
[INFO] No sources to compile
[INFO] 
[INFO] --- maven-surefire-plugin:2.10:test (default-test) @ rules ---
[INFO] No tests to run.
[INFO] Surefire report directory: /data/repositories/github/install_artifacts_sample/main_project/target/surefire-reports

-------------------------------------------------------
 T E S T S
-------------------------------------------------------

Results :

Tests run: 0, Failures: 0, Errors: 0, Skipped: 0

[INFO] 
[INFO] --- maven-jar-plugin:2.3.2:jar (default-jar) @ rules ---
[WARNING] JAR will be empty - no content was marked for inclusion!
[INFO] Building jar: /data/repositories/github/install_artifacts_sample/main_project/target/rules-1.0.0.jar
[INFO] 
[INFO] --- maven-install-plugin:2.3.1:install (default-install) @ rules ---
[INFO] Installing /data/repositories/github/install_artifacts_sample/main_project/target/rules-1.0.0.jar to /home/pantinor/.m2/repository/com/example/giallone/rules/1.0.0/rules-1.0.0.jar
[INFO] Installing /data/repositories/github/install_artifacts_sample/main_project/pom.xml to /home/pantinor/.m2/repository/com/example/giallone/rules/1.0.0/rules-1.0.0.pom
[INFO] ------------------------------------------------------------------------
[INFO] Reactor Summary:
[INFO] 
[INFO] Sample :: Multimodule ............................. SUCCESS [0.545s]
[INFO] Sample :: Dependencies ............................ SUCCESS [6.800s]
[INFO] Sample :: Main Project ............................ SUCCESS [0.344s]
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 7.816s
[INFO] Finished at: Thu Dec 20 13:07:03 GMT 2012
[INFO] Final Memory: 7M/117M
[INFO] ------------------------------------------------------------------------

Sunday, December 16, 2012

git - let's make errors ( and learn how to revert them )

It's not a secret that git is not a very easy tool to use.

I am able to use it more or less; but I always feel a little scared and confused about what's happening.
I feel that I want more informations.
I have followed some tutorial and read distractedly some book but, with too much information I always end up with just the feeling that I could do what I want to do. But I do not know how to do it.

I want to fix this situation so I have started to investigate more and I am trying to stick some key concept in my head, hoping to never forget them.

Let me start giving the credits for my source:

http://osteele.com/posts/2008/05/my-git-workflow
and
http://longair.net/blog/2009/04/16/git-fetch-and-merge/

I have found those articles interesting and helpful, the first in particular, but they are saying already too many things for the simplified model that I need.

Let's assume that you are already a git user.

You have a local repo, a remote one used to pull and push you work. And you also are aware of the existence of branches and you are using them. But still, with this basic knowledge you have the feeling of not being sure about your actions.

I guess that one of the key of this confusion is the role of the staging area. Please, note that in my discussion I am giving my understanding of it, and that I could be wrong. But nevertheless I can build my knowledge on this concept and be able to give my self a rationale behind it that helps me to gain confidence with the tool.

I like to think at the staging area, (that place where your modifications get tracked when you perform a git add operation, as a way to do "lighter commit". What I mean with lighter commit is that, since you are not forced to give a comment upon this action, you have less constraints. And since you are not even saving your action yet, you are clearly encouraged to perform add much more often than commit.

Let's give a scenario for our add use case: the process of adding some new functionality to your codebase; it probably involves the creation of new files and ideas just pop in your mind in an unordered fashion.

To give an example, let's pretend that you are creating 2 files with a reference to each other. Maybe a source code file and it's configuration file. You create the first, and start working on it. When you have finished to work on it you could think to commit it, but since your logical unit of work is not complete until you'll also create the configuration file you have the opportunity to perform the mentioned "lighter commit, i.e. a simple add. After you have finished the work with the configuration file, you have to add it to the index and now you can commit it. Or if you prefer you can do a git commit -a , to obtain the same result.

Since we have given a use case for the staging area, it should become easier to figure it's role in the git workflow. It's the logical place that stays between the current untracked directory and the committed (and safe) repository.

We are calling it a "place" so we can assume that we are interested in interacting with it. The already well known way to put things in it is the command:

git add


and it has 2 companion commands that you will use very often:

git diff


As the name suggests, it lists differences. But which ones? In its form without parameters, it lists differences between your current folder and the staging area.

touch test.txt
echo "text" >> test.txt
git add test.txt
echo "added1" >> test.txt
git diff
  returns this output:  
gittest$ git diff
 
diff --git a/test.txt b/test.txt
index 8e27be7..2db9057 100644
--- a/test.txt
+++ b/test.txt
@@ -1 +1,2 @@
 text
+added1

Ok we are now able to see differences between our working folder and the tracking context. We can obviously track the new modification, with an add command but we want also the opportunity to throw away our modification.

This is obtained with

git checkout .


Git checkout, without parameters (others than "dot", representing the current folder) will throw away the modification to your files and revert the status to the one tracked in the staging area with the previous add commands.

gittest$ git status


# On branch master
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#    new file:   test.txt
#
# Changes not staged for commit:
#   (use "git add <file>..." to update what will be committed)
#   (use "git checkout -- <file>..." to discard changes in working directory)
#
#    modified:   test.txt
#
 

gittest$ git checkout .


gittest$ git status
# On branch master
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#    new file:   test.txt
#



We have given a meaning to the staging area. And we can also think about it as the very first "environment" we are facing with, since every command without specific parameters works on staging.

Let's move on. We are now able to add or discard changings to the staging area. We also know how to persistently store the changings, via git commit. What we do not yet know how to do is to discard completely our staging area.

With a parallel with what we just did before, discarding staging is performed with:

git checkout HEAD .


That technically means that we are reverting to a specific commit point, the last one(HEAD).


Before testing this we have to perform a couple of interactions since inconsistent git behaviour doesn't allow us to execute the test right away. The reason is because our file was a "new" file and not a "modified" one. This breaks the symmetry but let me come back on this concept later.


@pantinor gittest$ git status
# On branch master
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#    new file:   test.txt
#
pantinor@pantinor gittest$ git commit -m "added new file"
[master f331e52] added new file
 1 file changed, 1 insertion(+)
 create mode 100644 test.txt
pantinor@pantinor gittest$ git status
# On branch master
nothing to commit (working directory clean)
pantinor@pantinor gittest$ echo "added" >> test.txt 
pantinor@pantinor gittest$ git status
# On branch master
# Changes not staged for commit:
#   (use "git add <file>..." to update what will be committed)
#   (use "git checkout -- <file>..." to discard changes in working directory)
#
#    modified:   test.txt
#
no changes added to commit (use "git add" and/or "git commit -a")
pantinor@pantinor gittest$ git add test.txt
pantinor@pantinor gittest$ git status
# On branch master
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#    modified:   test.txt
#
pantinor@pantinor gittest$ git checkout HEAD .
pantinor@pantinor gittest$ git status
# On branch master
nothing to commit (working directory clean)


We have just learnt how to revert to a clean situation.

We are now much less scared of the staging area.

But we are still bad git users. We always forget to branch before starting to modify a working folder as suggested here:

http://nvie.com/posts/a-successful-git-branching-model/

In my case it often goes like this: I have a stable situation, than I start to tweak something. But the tweaking is not linear and after some minutes I have lots of modified files.
Yes, I could stage them all and commit them, but I do not trust myself and I do not want to pollute the master branch. It would have been much better if I was on a dev branch from the beginning of my modifications. What I could do now?

We can create on the fly a branch and switch to it.

pantinor@pantinor gittest$ echo something >> test.txt 
pantinor@pantinor gittest$ git status
# On branch master
# Changes not staged for commit:
#   (use "git add <file>..." to update what will be committed)
#   (use "git checkout -- <file>..." to discard changes in working directory)
#
#    modified:   test.txt
#
no changes added to commit (use "git add" and/or "git commit -a")
pantinor@pantinor gittest$ git checkout -b dev
M    test.txt
Switched to a new branch 'dev'


On this new branch we will still accessing the shared staging area as you can see from my output:

pantinor@pantinor gittest$ git status
# On branch dev
# Changes not staged for commit:
#   (use "git add <file>..." to update what will be committed)
#   (use "git checkout -- <file>..." to discard changes in working directory)
#
#    modified:   test.txt
#
no changes added to commit (use "git add" and/or "git commit -a")



What we want to do now, is to add the working situation to the staging and to commit it, so to be able to flush the shared staging area.

pantinor@pantinor gittest$ git add .
pantinor@pantinor gittest$ git commit -m unstable
[dev 5d597b2] unstable
 1 file changed, 1 insertion(+)
pantinor@pantinor gittest$ git status
# On branch dev
nothing to commit (working directory clean)

pantinor@pantinor gittest$ cat test.txt 
text
something


and then, when we will go back to our master, we can find it free of all our experimental modification, not mature for the master branch:

pantinor@pantinor gittest$ git checkout master
Switched to branch 'master'
pantinor@pantinor gittest$ git status
# On branch master
nothing to commit (working directory clean)
pantinor@pantinor gittest$ echo test.txt 
test.txt


Great. Keeping our commands relatively simple and free of parameters and flag we are able to do all the errors that we are inevitable going to do anyway.

Let's now introduce another pattern to cope with our other typical errors. The situation is similar to the one just described, but a little worse. Again, we haven't branched before starting to play with the code, but this time we have also committed a couple of times before realizing that what we have committed is not as good as we thought. What we want to do this time, is to keep our unstable situation, but we want to move it away( hard reset) from the current branch.

Let's do a couple of commits:

pantinor@pantinor gittest$ git status
# On branch master
nothing to commit (working directory clean)
pantinor@pantinor gittest$ cat test.txt 
text
pantinor@pantinor gittest$ echo "modification1" >> test.txt 
pantinor@pantinor gittest$ git commit -a -m"first commit"
[master 9ad2aa8] first commit
 1 file changed, 1 insertion(+)
pantinor@pantinor gittest$ echo "modification2" >> test.txt 
pantinor@pantinor gittest$ git commit -a -m"second commit"
[master 7005a92] second commit
 1 file changed, 1 insertion(+)
pantinor@pantinor gittest$ cat test.txt 
text
modification1
modification2
pantinor@pantinor gittest$ git log
commit 7005a92a3ceee37255dc7143239d55c7c3467551
Author: Paolo Antinori <pantinor redhat.com="redhat.com">
Date:   Sun Dec 16 21:05:48 2012 +0000

    second commit

commit 9ad2aa8fae1cbd844f34da2701e80d2c6e39320e
Author: Paolo Antinori <pantinor redhat.com="redhat.com">
Date:   Sun Dec 16 21:05:23 2012 +0000

    first commit

commit f331e52f41a862d727869b52e2e42787aa4cb57f
Author: Paolo Antinori <pantinor redhat.com="redhat.com">
Date:   Sun Dec 16 20:20:15 2012 +0000

    added new file

At this point we want to move the last 2 commit to a different branch:

git branch unstable


We created a new branch, but we haven't switched to it.

The just created new branch has obviously everything that was present at the time of its creation, i.e. the 2 commits that we want to remove. So we can revert our current branch to a previous commit, discarding completely the recent ones that will remain available on the unstable branch.

to see what's the commit that we want to revert to:

git log


we need to read the hashcode associated with the commit, to be able to perform our rollback(hard reset):

pantinor@pantinor gittest$ git reset --hard f331e52f41a862d727869b52e2e42787aa4cb57f
HEAD is now at f331e52 added new file


If you now execute a git status or a git log, you will see no trace of the unstable commit, that are instead accessible in the unstable branch.

On current:
 

pantinor@pantinor gittest$ cat test.txt 
text
pantinor@pantinor gittest$ git log
commit f331e52f41a862d727869b52e2e42787aa4cb57f
Author: Paolo Antinori <pantinor redhat.com="redhat.com">
Date:   Sun Dec 16 20:20:15 2012 +0000

    added new file



 On branch:

pantinor@pantinor gittest$ git checkout unstable 
Switched to branch 'unstable'
pantinor@pantinor gittest$ cat test.txt 
text
modification1
modification2
pantinor@pantinor gittest$ git log
commit 7005a92a3ceee37255dc7143239d55c7c3467551
Author: Paolo Antinori <pantinor redhat.com="redhat.com">
Date:   Sun Dec 16 21:05:48 2012 +0000

    second commit

commit 9ad2aa8fae1cbd844f34da2701e80d2c6e39320e
Author: Paolo Antinori <pantinor redhat.com="redhat.com">
Date:   Sun Dec 16 21:05:23 2012 +0000

    first commit

commit f331e52f41a862d727869b52e2e42787aa4cb57f
Author: Paolo Antinori <pantinor redhat.com="redhat.com">
Date:   Sun Dec 16 20:20:15 2012 +0000

    added new file




Friday, November 9, 2012

REST Invocation With Maven

Recently I had to invoke some REST service in one of my Maven builds.

I had never did it before but I was expecting to find some ready to use component that could allow me to do all the things that I needed directly from configuration but it wasn't the case.

I did the typical search to see what was available and I have found some good tip here and there.

But the conclusion is that there is not a ready "off the shelf" component.

The 2 most practical options seem to be:

- use an Ant GET Task
- embed Groovy code in you r script

Since the first option work only with the verb GET I decided to use the Groovy approach.

Let's say that we want to invoke a service via POST like this:

 
pantinor@pantinor maven_rest$
    curl -d appid=YahooDemo -d query=madonna -d \ 
    context="renaissance favored the Virgin Mary for inspiration" \ 
    http://search.yahooapis.com/ContentAnalysisService/V1/termExtraction


Produces this output:

virgin mary
renaissance
inspiration


An example taken from http://developer.yahoo.com/search/content/V1/termExtraction.html


This is one way to do that in Maven

Add some useful dependency

        
            org.codehaus.groovy.modules.http-builder
            http-builder
            0.5.1
        
 
Specify the Groovy plugin
   
    org.codehaus.groovy.maven
    gmaven-plugin
    1.0
    
     
      generate-resources
      
       execute
      
      
       
       ...
       
      
     
    
   
Add add the proper Groovy code

import groovyx.net.http.RESTClient
import groovy.util.slurpersupport.GPathResult
import static groovyx.net.http.ContentType.URLENC
import static groovyx.net.http.ContentType.XML

yahoo = new RESTClient('http://search.yahooapis.com/ContentAnalysisService/V1/termExtraction')

def response = yahoo.post(
    contentType: XML,
    requestContentType: URLENC,
    body: [appid:"YahooDemo", query:"madonna", context:"renaissance favored the Virgin Mary for inspiration"] 
)
log.info "yahoo response data: ${response.data}"

This is the full pom.xml file


 4.0.0
 test
 maven-rest
 1.0.0

 Maven Rest Example

 
        
            org.codehaus.groovy.modules.http-builder
            http-builder
            0.5.1
        
     
 
     

   
    org.codehaus.groovy.maven
    gmaven-plugin
    1.0
    
     
      generate-resources
      
       execute
      
      
       
        <![CDATA[
import groovyx.net.http.RESTClient
import groovy.util.slurpersupport.GPathResult
import static groovyx.net.http.ContentType.URLENC
import static groovyx.net.http.ContentType.XML

yahoo = new RESTClient('http://search.yahooapis.com/ContentAnalysisService/V1/termExtraction')

def response = yahoo.post(
    contentType: XML,
    requestContentType: URLENC,
    body: [appid:"YahooDemo", query:"madonna", context:"renaissance favored the Virgin Mary for inspiration"] 
)
log.info "yahoo response data: ${response.data}"
        ]]>
       
      
     
    
   
  
 





That will produce the following output:

pantinor@pantinor maven_rest$ 
    mvn install | grep -i "yahoo"
    [INFO]  yahoo response data: virgin maryrenaissanceinspiration

Monday, August 27, 2012

Fedora 17 - Google Calendar Integration

I have just found this useful post about how to integrate your Google Calendar with Gnome3 Calendar:

http://www.webupd8.org/2011/09/google-calendar-gnome-shell-integration.html


I have just tried and it's working great!

( I cannot take a snapshot since the key is not working when the Calendar Overlay is open =P )

Friday, August 24, 2012

Gnome-shell: Show contact list

I have recently switched from RHEL 6 to Fedora 17.

I found myself less productive during the first days and I had the opportunity to agree with people that identify RHEL as a good distribution for enterprises and for people that need to be productive from the beginning, without losing time to adapt to a new environment, even if this could be winning in the long run.

But after this thoughts, that I still believe are true, I started to enjoy the experience of Fedora and Gnome3. I think they are able to satisfy you if you are the kind of person that likes to tweak his system and likes to experiment with it.

 In Fedora 17, one of the biggest area in which you can play with settings is Gnome3.

 Like other people I do believe that some of the decision of the developers have been to radical and that it's not giving out of the box the best experience that it could. A typical example is the fact that they've hidden the shutdown functionalities and that you have to press ALT to see them, something that everyone could agree is not intuitive at all. 

But maybe the idea behind all this radical decisions is that they want to offer a minimal customization, to allow people to change everything that they do not like and to extend the behaviour, a la Firefox.


And talking specifically about this customization, one extension that I've found useful is Empathy Contact List in UserMenu https://extensions.gnome.org/extension/396/empathy-contact-list-in-usermenu/


"Shows an Empathy Contact List launcher in UserMenu"


Something that is really useful in my opinion because otherwise, if you are not using external sw like Pidgin, you have to perform a long set of action to open a message window to one of your contact:

- you have to go in expose mode
- you have to type the name of the contact to open his  panel
- you have to click on the message button

Only after you have done all this you can have a message window.
Like others said, I do not think this is very handy.

The linked extension allows you to have easy access to the contact list. Stop.



But there is a problem. It doesn't work in Fedora 17.

The reason for this is that the code of the extension is trying to execute empathy.desktop, the program integrated in Gnome3 to provide instant messaging functionality, but in Fedora 17, the shortcut file, to execute the program has a slightly different name: fedora-empathy.desktop .

To correct this and fix the problem this is what you have to do:

1) open the source code of the extension here

vi ~/.local/share/gnome-shell/extensions/empathy-contacts-in-usermenu@rtt.uy/extension.js

2) edit line 19 changing from 'empathy.desktop' to 'fedora-empathy.desktop' and save

3) restart Gnome3 with ALT+F2 followed by the command r

Enjoy your functionality!


The last thing that I'd like to add is the way to access useful information when you try to understand what is happening with an extension that is not behaving properly. There is a log file that gives you lots of useful information.

The approach I suggest you is to execute this command in a shell before starting to use the problematic extension:

tail -f ~/.xsession-errors

In this way you can clearly see what is wrong. This was my log file, that led me to the fix:
    JS ERROR: !!!   Exception in callback for signal: activate
    JS ERROR: !!!     message = '"Shell.AppSystem.get_default().lookup_app("empathy.desktop") is null"'
    JS ERROR: !!!     lineNumber = '19'
    JS ERROR: !!!     fileName = '"/home/pantinor/.local/share/gnome-shell/extensions/empathy-contacts-in-usermenu@rtt.uy/extension.js"'
    JS ERROR: !!!     stack = '"([object Object],[object _private_Clutter_Event])@/home/pantinor/.local/share/gnome-shell/extensions/empathy-contacts-in-usermenu@rtt.uy/extension.js:19

Wednesday, August 22, 2012

Fedora 17 - Spoof Mac Address

I am not sure if this feature it's always been there, but I have recently discovered that Fedora's connection manager allows you to set in the network configuration the desired spoofed mac address.




This is much better than changing it manually with a command like this every time:

sudo ifconfig wlan0 hw ether 00:00:00:00:00:00


If I only had this during Residence Evil period...

Wednesday, August 8, 2012

Git: I wasn't the only one...

To have mixed feelings about the tool and to find it syntax not that clear.

https://steveko.wordpress.com/2012/02/24/10-things-i-hate-about-git/


Usually I have problems with syntaxes, It takes me a lot of time to remember the new ones.

Git introduces some keyword. Ok. You know that you have to put some effort to learn the new "verbs".

But just like the inconsistency around all Linux programs that share the same flags and invocation style only rarely, even Git itself show a clear lack of consistency.

Tuesday, August 7, 2012

JVM Performance Tuning Video

http://www.infoq.com/presentations/Extreme-Performance-Java#


I'd like to suggest to anyone that has to deal with Java and JEE development this video of Charlie Hunt, Architect of Performance Engineering at Salesforce.com , that give you some explanation and tips about Java memory management mechanism and tools to analyse the related data.

Saturday, August 4, 2012

Gollum Personal Wiki on Openshift

My tabs are begging me to be closed. Even Firefox asks the same.

I have decided that I need to store some of that information somewhere, and that I couldn't just rely on Bookmarks mechanism since I haven't read properly all of those pages and I wouldn't be able to search for the info I would need.


So I have decided I needed a personal wiki.

I wanted something that I could easily push on the web, on Openshift ideally.


I've found out this post:

http://www.highlevelbits.com/2011/11/my-precious-wiki.html


That suggest the usage of Gollum, a personal Wiki based on Sinatra/Rails.

You do not need to know anything about the underlying technology to deploy and use it.

When you want to use it offline, you just have to un

gollum


and the command will execute an in memory webserver that will host locally your wiki. You can start to use it, to read and write what you need and once in a while you just have to push to Openshift git repository to publish all your work online.

The tutorial is a little outdated but it's easy to understand what to change to obtain the result.

If you need any help just drop a line ;)


Note:

Fedora needs  python-pygments and python-develfor the code syntax features


Thursday, August 2, 2012

Gnome Extensions Installation Silent Error

I was one of those unlucky ones not able to install Gnome Extensions via the website, on my Fedora 17.

 I've found out I wasn't the only one but we were not a big number and there was not a clear solution to our problem.

 Apparently I have found that is somewhat related to SSL and the time set in you laptop. Yes. I do not why, but it was definitely my case.  

This is the error I was receiving:

JS ERROR: !!!   Exception was: TypeError: info is null
JS ERROR: !!!     lineNumber = '83'JS ERROR: !!!     fileName = '"/usr/share/gnome-shell/js/ui/extensionSystem.js"'
JS ERROR: !!!     stack = '"([object _private_Soup_SessionAsync],[object _private_Soup_Message])@/usr/share/gnome-shell/js/ui/extensionSystem.js:83"'
JS ERROR: !!!     message = '"info is null"'

If you are also unable to join your Google account to your Gnome 3 profile, ( Check with the Google one since the other options were working fine ) you will probably have my same problem.

For some reason that I cannot explain it seems that the clock or the timezone set on you Linux are involved in the problem.

 Try to change them switching form either network updated to something else like New York timezone and repeat the process.
It's enough to check if you can join the Google account.

As soon as you see you are able, also the extension installation is fixed.

Monday, July 30, 2012

Class Broswer Plugin for Gedit

I have just installed a useful plugin for gedit on Fedora 17:

 https://launchpad.net/gedit-classbrowser3g

It provides you a nice pane with method and classes, useful when you are inspecting a portion of code and you do not want to open it in the start to load Eclipse. To work correctly it requires ctags package to be installed too.

Give it a try!

And since it's always nice to stash information all in one place I've also added these ones:

 https://code.google.com/p/advanced-find/

 https://github.com/jonocodes/GeditSplitView

Monday, June 25, 2012

Open Shift on Feodra 17

I have just moved from RHEL 6 to Fedora 17. Not completely seamless but probably I had part in the mess. Anyway it's been quite simple and still feeling more a Windows user than a Linux one, seeing that to restore my previous programs and configurations it is just a matter of moving files, like I used to do on Windows choosing Portable Application make me feel happy (and save a lot of time)

I decided I needed to blog here since I have found a problem with Red Hat Open Shift installation procedure.

If you follow the official steps on Open Shift site you'll receive a 404 error, very disappointing.

But the bug has already been tracked:

https://bugzilla.redhat.com/show_bug.cgi?id=826808 

Anyway it seems that Fedora already includes the right packages, they are just with a slightly different name:

yum search rhc

#will lead you to: 

yum install rubygem-rhc



that will provide you the rhc command!


Sunday, March 4, 2012

RHEL 6 - Toggle trackpad when mouse is plugged in/out

Too often on my RHEL system I hit the mousepad when writing or doing something else, with the result of typing in the wrong part of the document.
This is even more annoying when I am sitting at my desk, with my mouse plugged.
I know that there is a setting to disable the mousepad when typing but I wanted something more robust.

For this reason here is a little guide about how I managed to automatically disable the mousepad when I plug in a usb mouse and how to enable it back when I unplug it.

You need some utility to query your mice.

sudo yum install xorg-x11-apps

Now we can have a list of the recognized plugged input devices on your system:

$ xinput list
⎡ Virtual core pointer                     id=2 [master pointer  (3)]
⎜   ↳ Virtual core XTEST pointer               id=4 [slave  pointer  (2)]
⎜   ↳ TPPS/2 IBM TrackPoint                    id=13 [slave  pointer  (2)]
⎜   ↳ Macintosh mouse button emulation         id=14 [slave  pointer  (2)]
⎜   ↳ Logitech USB Laser Mouse                 id=16 [slave  pointer  (2)]
⎜   ↳ SynPS/2 Synaptics TouchPad               id=15 [slave  pointer  (2)]
⎣ Virtual core keyboard                    id=3 [master keyboard (2)]
    ↳ Virtual core XTEST keyboard              id=5 [slave  keyboard (3)]
    ↳ ThinkPad Extra Buttons                   id=6 [slave  keyboard (3)]
    ↳ AT Translated Set 2 keyboard             id=7 [slave  keyboard (3)]
    ↳ Lid Switch                               id=8 [slave  keyboard (3)]
    ↳ Integrated Camera                        id=9 [slave  keyboard (3)]
    ↳ Sleep Button                             id=10 [slave  keyboard (3)]
    ↳ Video Bus                                id=11 [slave  keyboard (3)]
    ↳ Power Button                             id=12 [slave  keyboard (3)]

My laptop has a touchpad(id=15) and a trackpoint(id=13).
And you can see an entry for my usb mouse (id=16)

If you just want to disable manually the mousepad or any other device it is quite easy.

It is just a matter of:


xinput --set-prop "SynPS/2 Synaptics TouchPad" "Device Enabled" 1 # to enable
xinput --set-prop "SynPS/2 Synaptics TouchPad" "Device Enabled" 0 # to disable


Now if we want to automatically execute this commands when the mouse is plugged/unplugged we need to use udev.

sudo yum install udev

We create a new rules file in udev configuration folder:

sudo gedit /etc/udev/rules.d/61-touchpad.rules

And add this code:

# 61-touchpad.rules
#
# this rules file must be named 61* or later because it won't work
# unless it runs after '/lib/udev/rules.d/60-persistent-input.rules'
#
# NOTE: will only affect DISPLAY :0
#
# run:
#   udevadm test --action=add /sys/devices/platform/i8042/serio1/input/input6/mouse1
# or similar to test the following rules
#

ACTION=="add", SUBSYSTEM=="input",  ENV{DISPLAY}=":0.0", DEVPATH=="*/mouse?", RUN+="/usr/bin/xinput --set-prop 'SynPS/2 Synaptics TouchPad' 'Device Enabled' 0"
ACTION=="remove", SUBSYSTEM=="input",  ENV{DISPLAY}=":0.0", DEVPATH=="*/mouse?", RUN+="/usr/bin/xinput --set-prop 'SynPS/2 Synaptics TouchPad' 'Device Enabled' 1"

And we have done!

Try to plug/unplug if it is behaving like expected!


In case of problems there is a way to debug udev events, in case the rules we defined do not apply exactly to your hardware configuration:

sudo killall udevd
sudo udevd --debug-trace --debug

To restart udevd when you have finished the debug:

/sbin/start_udev

Useful link:

https://wiki.archlinux.org/index.php/Touchpad_Synaptics#Disable_touchpad_upon_external_mouse_detection