Wednesday, January 21, 2015

Install .dmg files on Mac OS X using command line

Sometimes you need to install .dmg files on Mac using command line. You first need to mount the .dmg as a drive:

hdiutil mount jdk-8u20-macosx-x64.dmg


Now you'll see a drive is created under /Volumes :

ll /Volumes/
drwxr-xr-x 6 Rafi staff 272 Jul 30 23:31 JDK 8 Update 20
cd /Volumes/JDK\ 8\ Update\ 20/
ll
-rwxr-xr-x@ 1 Rafi staff 219555315 Jul 30 23:31 JDK 8 Update 20.pkg


You can check what target paths are available for the installation this way:

sudo installer -pkg JDK\ 8\ Update\ 20.pkg -dominfo


You should see something like:
LocalSystem


Now you can install the .pkg file with the installer of Mac OS X:

sudo installer -pkg JDK\ 8\ Update\ 20.pkg -target LocalSystem

If you want to follow the log of the installer:

tail -f /var/log/install.log

Tuesday, August 26, 2014

sudo: sorry, you must have a tty to run sudo

If you're trying to execute a command with "sudo" permission in a remote server using ssh, for example:

ssh user@remoteServer "sudo ls"

and get this error:
sudo: sorry, you must have a tty to run sudo

Then this means that the remote server doesn't allow arbitrary screen-based programs to run sudo on that server. there are several ways to work around this problem.

Using "-t" option:

You can use -t option to make your command work.
ssh user@remoteServer "sudo ls"

-t option enables arbitrary screen-based programs on a remote server.

Using "--session-command" option:

You can execute the command this way:

ssh user@remoteServer su --session-command="ls"

You can also use a specific user (for example "admin") to run the command in the remote server this way:

ssh user@remoteServer su --session-command="ls" admin

Changing the "requiretty" option in sudoers file in remote server:

The above were temporary solutions, if you want to have a more permanent solution then you must have the write access to /etc/sudoers file in the remote server.

You should see this line in /etc/sudoers file (in the remote server):

Defaults    requiretty

Comment out the line and save the file:

# Defaults    requiretty

If the "requiretty" option is set then "sudo" can only be run from a real tty (from a login session). Arbitrary logins or scripts cannot perform "sudo" with this option enabled. Commenting it out enables the arbitrary logins or scripts to perform "sudo".

For more info have a look at the page I learned this from:
http://www.cyberciti.biz/faq/linux-unix-bsd-sudo-sorry-you-must-haveattytorun/

Thursday, April 3, 2014

"<useUniqueVersions>" for pom.xml

If your RPM is building successfully, but when you try to run that component after installing, you get java.lang.NoClassDefFoundError for some class which you know exists in the classpath, then probably the component version (or name) in your Manifest.MF file doesn't match the JAR file included in the classpath (for example MANIFEST.MF expects released version, but classpath contains SNAPSHOT version). In this situation, we can specify in the maven-jar-plugin inside pom.xml not to look for the Unique version of JAR with this tag:

<useUniqueVersions>false</useUniqueVersions>

Complete example:
         <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-jar-plugin</artifactId>
            <executions>
               <execution>
                  <goals>
                     <goal>jar</goal>
                  </goals>
                  <phase>package</phase>
               </execution>
            </executions>
            <configuration>
               <archive>
                  <manifest>
                     <addClasspath>true</addClasspath>
                     <useUniqueVersions>false</useUniqueVersions>
                  </manifest>
               </archive>
            </configuration>
         </plugin>

Now build your rpm and try again, hopefully it fixes it.
For more info: https://maven.apache.org/shared/maven-archiver/examples/classpath.html#aSnapshot

Thursday, March 27, 2014

Creating local yum repository and using it

Sometimes it is needed to create a local yum repository when you want yum to download packages from a local repository instead of the main repository. It is very much needed when you don't want to commit your changes to a branch which is being developed by other teams. This approach is very useful when some of the packages are available in both the repositories, but you only want yum to download from your local repository for those packages.

Step-by-step guide

Before following the steps, you should have your jenkins setup in a VM (i.e. avoid the main jenkins server). Perform the steps in the same vm.

  • Creating the yum repo
    • Install createrepo: "yum install createrepo"
    • Create the repository directory: "mkdir -p /opt/repo/RPMS/noarch"
    • [Follow this page for more info: http://www.techrepublic.com/blog/linux-and-open-source/create-your-own-yum-repository/609/ ]
    • To be able to use the repository through http, create a file /etc/httpd/conf.d/repo.conf:
                     Alias /repo "/opt/repo/RPMS/"

                     <Directory "/opt/repo/RPMS/">
                     Options +Indexes
                     FileETag MTime Size
                     AllowOverride None
                     Order allow,deny
                     Allow from all
                     </Directory>

    • Restart httpd: sudo service httpd restart
    • Now you'll be able to access the repository through: http://<server_address>/repo/noarch/

  • [This step is only required if you want jenkins to build rpm and automatically put in your repository. If you put your rpms manually then skip this step] Create the jenkins job for the specific branch in your jenkins installation
    • In the post step of the job configuration, select "Run only if build succeeds" and put "execute shell":

                     if [ -f ${WORKSPACE}/target/rpm/RPMS/noarch/*\.rpm ];
                     then
                     /bin/cp -f ${WORKSPACE}/target/rpm/RPMS/noarch/*\.rpm /opt/repo/RPMS/noarch /usr/bin/createrepo /opt/repo/RPMS/noarch
                     fi

    • The above will copy the rpm built rpm to the yum repository directory.
  • In the target server (i.e. where you want to run yum) install yum-priorities: 
                     yum install yum-priorities

          This plugin enables yum to search for packages based on priority.

  • Setup the repo file like (for example /etc/yum.repos.d/my-repo.repo):


                     [main-repo]
                     name=main-repo
                     baseurl=http://<server_address_of_main_repo>/repo/LATEST/
                     gpgcheck=0
                     enabled=1
                     metadata_expire=1
                     priority=2

                     [my-repo]
                     name=my-repo
                     baseurl=http://<server_address>/repo/noarch/
                     gpgcheck=0
                     enabled=1
                     metadata_expire=1
                     priority=1

          The above tells yum to first check in my-repo repo, if not found then to go to main-repo (note the priority=1).

Now you are ready to use your yum repository. As soon as the rpm is built by jenkins, it can be fetched using yum.

Wednesday, February 5, 2014

Don't mess with /System/Library/Frameworks/JavaVM.framework/Versions/Current in Mac OS X

I had both JDK1.6 and JDK1.7 installed in OS X 10.9 (Mavericks).  I was trying to force java to use default JDK version to 1.6. I thought its going to be fine if I change the soft link:

/System/Library/Frameworks/JavaVM.framework/Versions/Current -> A

to this:

/System/Library/Frameworks/JavaVM.framework/Versions/Current -> CurrentJDK

where CurrentJDK points to /System/Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents (the JDK 1.6).

But after doing so, I got this error when trying to compile an application that depended on AWT libraries:

java[5617:d07] Apple AWT Startup Exception : -[__NSCFString appendString:]: nil argument
java[5642:d07] Apple AWT Restarting Native Event Thread

Also "/usr/libexec/java_home" (which gives the java_home) was also giving "command not found" error.

After doing some googling, I found that I shouldn't mess with /System/Library/Frameworks/JavaVM.framework/Versions/Current. So it should be kept as it was (pointed to A). Rather just change the link of /usr/bin/java to /System/Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/Home/bin/java:

sudo rm /usr/bin/java
sudo ln -s /System/Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/Home/bin/java /usr/bin/java

Then /usr/libexec/java_home should automatically point to /System/Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/Home.

Now you should set your $JAVA_HOME in your ~/.bash_profile file like this:

export JAVA_HOME=$(/usr/libexec/java_home)

Then source the ~/.bash_profile file:

source ~/.bash_profile

You're all set now with your preferred java version.

Thursday, January 23, 2014

Getting started with GIT basics

Previously I've blogged about making a local SVN repository. This time I'm going to talk about GIT, another version control system. For many reasons, GIT has advantages over SVN (which I'm going to blog about some other time). It is also a little bit complex compared to SVN. For example, if you modify a file in SVN, then that modification persists in your local machine even without committing. Then later on you can commit that modification so the changes are also applied to the main repository. But it's a little different in GIT. In GIT you have the repository in your local machine (whereas in SVN your local copy acts just like a client). After modifying a file in GIT repository, you need to commit that change just to make sure that the changes persist in your local repository for the current branch (not in the original repository). If you modify a file but don't commit, then you can't push it to the original repository. If you want your modification to be available in other branches, then you'll need to merge the two branches. At last, you'll need to "push" your changes to the original repository.

There are plenty of graphical tools to manage GIT operations, you'll never have to think about the command line if you use those tools. But its good to know what commands are working in the background. I really like SourceTree as a git manager. If you use Eclipse as your IDE, then you can also install the EGit plugin which provides very nice GIT Team management.

Here are some very basic GIT commands to get you started with it, provided that you already have access to a GIT repository somewhere and you've installed GIT in your local machine. You might need to setup a ssh-key based authentication from your computer to the original repository (depending on the settings of the repository).

Let's say the remote repository exists at ssh://git-user@server01/git-test.git and you want to clone only develop branch (which is analogous to trunk in SVN) for now.

1. From command line (in windows, install the command line tool for GIT) put this command to create the local repository:
  • git clone -b develop ssh://git-user@server01/git-test.git
2. It will create a new folder named git-test. Enter the folder and you can create your own branch (and you'll be switched to this new branch):
  • git checkout -b rafis_branch
3. Now there are two branches in your local machine, namely develop and rafis_branch. You can see the branches with this command:
  • git branch -l
You'll see something like:
develop
* rafis_branch

The * denotes the current branch you're in.

4. Modify or add a new file. Now at this point you still haven't committed your modification to any branches. So if you change the current branch without committing, you'll see the same changes in other branches (in your local repository) as well. You can check the current status with this command:
  • git status
5. If you've added a new file, then use this command to track this file:
  • git add new_file.txt
We still haven't committed the changes (we've merely added this file for tracking by GIT).

If you've modified a file, then the above command is not needed since the file is already tracked by GIT. commit the changes to the current branch (also needed for newly tracked file):
  • git commit -am "Added new_file.txt and modified file.txt"
The changes will now be committed to the current branch. So now if you change the branch, then you can't see the modifications made. For example, if you use graphical interface to see the file, then you must be in the branch (with terminal) where you've committed the changes. If you switch to other branch, then you can't see the new file or the modified file in the graphical interface. All these information are kept in the hidden folder called .git in the repository root.

6. Now lets make the changes available in other branch as well. Lets say you've committed the changes in rafis_branch. Now you want the change to be merged in develop branch. Then first switch to the develop branch:
  • git checkout develop
7. Before merging the changes from rafis_branch, make sure that you're upto date with the origin in this branch. So you'll need to pull from the origin develop branch:
  • git pull origin develop 
This will pull any new changes made in the develop branch in the origin repository. This is required to make sure you don't put any conflict in the origin. Rather merge in the local repository, fix conflicts if any, then push to the origin repository when you're convinced that there'll be not conflicts in the files.

8. Now you can merge the changes of rafis_branch to develop branch:
  • git merge rafis_branch
9. After merging and fixing any conflicts in the files, now its time to push your changes to the develop branch of the origin:
  • git push origin develop
Voila, you've just pushed your first GIT commit to the origin repository. Now when someone pulls from the origin repository, they'll get the changes you made.

10. You can continue working on your new branch (don't forget to switch to that branch "git checkout rafis_branch"). If you think that you no longer need the branch you created in your local machine, then you can delete it (and can create again later on):
  • git branch -d rafis_branch
Now that branch doesn't exist anymore. So the command "git branch -l" will not show that branch now.



Setting the locale in UNIX environment

Recently I upgraded from OS X 10.8 (Mountain Lion) to 10.9 (Mavericks), and noticed that my locale is set to (you can check this with command "locale"):

LANG="C"
LC_COLLATE="C"
LC_CTYPE="C"
LC_MESSAGES="C"
LC_MONETARY="C"
LC_NUMERIC="C"
LC_TIME="C"
LC_ALL="C"

You'll experience some encoding problems with this locale. Also when you want to remote login to a Redhat machine, you'll encounter some warning. To set the locale to your preferred one (for me its "en_US.UTF-8"), you'll need to add these two lines in your ~/.bash_profile file:

export LC_ALL=en_US.UTF-8
export LANG=en_US.UTF-8

That's all, now you can open a new session (or just use this command within the running session: "source ~/.bash_profile" ) with your terminal and check the locale again. It should be now like this:

LANG="en_US.UTF-8"
LC_COLLATE="en_US.UTF-8"
LC_CTYPE="en_US.UTF-8"
LC_MESSAGES="en_US.UTF-8"
LC_MONETARY="en_US.UTF-8"
LC_NUMERIC="en_US.UTF-8"
LC_TIME="en_US.UTF-8"
LC_ALL="en_US.UTF-8"