If you don't have root permission you will not be able to install a module in the usual place on a shared user system. If you do not have root access you may get errors like:
$ make install
Warning: You do not have permissions to install into
/usr/local/lib/perl5/site_perl/5.005/i386-freebsd at
/usr/libdata/perl/5.00503/ExtUtils/Install.pm line 62.
mkdir /usr/local/lib/perl5/site_perl/5.005/CGI/Simple:
Permission denied at /usr/libdata/perl/5.00503/ExtUtils/Install.pm line 120
*** Error code 2
This is easy to get around. You just install it locally in your home directory. Make a directory called say /lib in your home directory like this:
# first navigate to your home directory
$ cd ~
# now make a directory called lib
# on UNIX
$ mkdir lib
# on Win32
C:\> md lib
Now you have a directory called ~/lib where the ~ represents the path to your home dir. ~ literally means your home dir but you knew that already. All you need to do is add a modifier to your perl Makefile.PL command
$ perl Makefile.PL PREFIX=~/lib LIB=~/lib
This tell MakeMaker to install the files in the lib directory in your home directory. You then just make/nmake as before. To use the module you just need to add ~/lib to @INC. See Simple Module Tutorial for full details of how. In a nutshell the top of your scripts will look like this:
#!/usr/bin/perl -w
use strict;
# add your ~/lib dir to @INC
use lib '/usr/home/your_home_dir/lib/';
# proceed as usual
use Some::Module;
Source: http://www.perlmonks.org/?node_id=128077
Monday, September 12, 2011
Thursday, September 01, 2011
Factory methods in Java
This story appeared on JavaWorld at
http://www.javaworld.com/javaworld/javaqa/2001-05/02-qa-0511-factory.html
Factory methods
How do you employ factory methods to your best advantage?
By Tony Sintes, JavaWorld.com, 05/11/01
While going through "Polymorphism in its purest form," I saw the unfamiliar term factory method. Could you please describe what a factory method is and explain how I can use it?
Factory method is just a fancy name for a method that instantiates objects. Like a factory, the job of the factory method is to create -- or manufacture -- objects.
Let's consider an example.
Every program needs a way to report errors. Consider the following interface:
Listing 1
public interface Trace {
// turn on and off debugging
public void setDebug( boolean debug );
// write out a debug message
public void debug( String message );
// write out an error message
public void error( String message );
}
Suppose that you've written two implementations. One implementation (Listing 2) writes the messages out to the command line, while another (Listing 3) writes them to a file.
Listing 2
public class FileTrace implements Trace {
private java.io.PrintWriter pw;
private boolean debug;
public FileTrace() throws java.io.IOException {
// a real FileTrace would need to obtain the filename somewhere
// for the example I'll hardcode it
pw = new java.io.PrintWriter( new java.io.FileWriter( "c:\trace.log" ) );
}
public void setDebug( boolean debug ) {
this.debug = debug;
}
public void debug( String message ) {
if( debug ) { // only print if debug is true
pw.println( "DEBUG: " + message );
pw.flush();
}
}
public void error( String message ) {
// always print out errors
pw.println( "ERROR: " + message );
pw.flush();
}
}
Listing 3
public class SystemTrace implements Trace {
private boolean debug;
public void setDebug( boolean debug ) {
this.debug = debug;
}
public void debug( String message ) {
if( debug ) { // only print if debug is true
System.out.println( "DEBUG: " + message );
}
}
public void error( String message ) {
// always print out errors
System.out.println( "ERROR: " + message );
}
}
To use either of these classes, you would need to do the following:
Listing 4
//... some code ...
SystemTrace log = new SystemTrace();
//... code ...
log.debug( "entering loog" );
// ... etc ...
Now if you want to change the Trace implementation that your program uses, you'll need to edit each class that instantiates a Trace implementation. Depending upon the number of classes that use Trace, it might take a lot of work for you to make the change. Plus, you want to avoid altering your classes as much as possible.
A factory method lets us be a lot smarter about how our classes obtain Trace implementation instances:
Listing 5
public class TraceFactory {
public static Trace getTrace() {
return new SystemTrace();
}
}
getTrace() is a factory method. Now, whenever you want to obtain a reference to a Trace, you can simply call TraceFactory.getTrace():
Listing 6
//... some code ...
Trace log = new TraceFactory.getTrace();
//... code ...
log.debug( "entering loog" );
// ... etc ...
Using a factory method to obtain an instance can save you a lot of work later. In the code above, TraceFactory returns SystemTrace instances. Imagine again that your requirements change and that you need to write your messages out to a file. However, if you use a factory method to obtain your instance, you need to make only one change in one class in order to meet the new requirements. You do not need to make changes in every class that uses Trace. Instead you can simply redefine getTrace():
Listing 7
public class TraceFactory {
public static Trace getTrace() {
try {
return new FileTrace();
} catch ( java.io.IOException ex ) {
Trace t = new SystemTrace();
t.error( "could not instantiate FileTrace: " + ex.getMessage() );
return t;
}
}
}
Further, factory methods prove useful when you're not sure what concrete implementation of a class to instantiate. Instead, you can leave those details to the factory method.
In the above examples your program didn't know whether to create FileTrace or SystemTrace instances. Instead, you can program your objects to simply use Trace and leave the instantiation of the concrete implementation to a factory method.
About the author
Tony Sintes is a principal consultant at BroadVision. A Sun-certified Java 1.1 programmer and Java 2 developer, he has worked with Java since 1997.
http://www.javaworld.com/javaworld/javaqa/2001-05/02-qa-0511-factory.html
Factory methods
How do you employ factory methods to your best advantage?
By Tony Sintes, JavaWorld.com, 05/11/01
While going through "Polymorphism in its purest form," I saw the unfamiliar term factory method. Could you please describe what a factory method is and explain how I can use it?
Factory method is just a fancy name for a method that instantiates objects. Like a factory, the job of the factory method is to create -- or manufacture -- objects.
Let's consider an example.
Every program needs a way to report errors. Consider the following interface:
Listing 1
public interface Trace {
// turn on and off debugging
public void setDebug( boolean debug );
// write out a debug message
public void debug( String message );
// write out an error message
public void error( String message );
}
Suppose that you've written two implementations. One implementation (Listing 2) writes the messages out to the command line, while another (Listing 3) writes them to a file.
Listing 2
public class FileTrace implements Trace {
private java.io.PrintWriter pw;
private boolean debug;
public FileTrace() throws java.io.IOException {
// a real FileTrace would need to obtain the filename somewhere
// for the example I'll hardcode it
pw = new java.io.PrintWriter( new java.io.FileWriter( "c:\trace.log" ) );
}
public void setDebug( boolean debug ) {
this.debug = debug;
}
public void debug( String message ) {
if( debug ) { // only print if debug is true
pw.println( "DEBUG: " + message );
pw.flush();
}
}
public void error( String message ) {
// always print out errors
pw.println( "ERROR: " + message );
pw.flush();
}
}
Listing 3
public class SystemTrace implements Trace {
private boolean debug;
public void setDebug( boolean debug ) {
this.debug = debug;
}
public void debug( String message ) {
if( debug ) { // only print if debug is true
System.out.println( "DEBUG: " + message );
}
}
public void error( String message ) {
// always print out errors
System.out.println( "ERROR: " + message );
}
}
To use either of these classes, you would need to do the following:
Listing 4
//... some code ...
SystemTrace log = new SystemTrace();
//... code ...
log.debug( "entering loog" );
// ... etc ...
Now if you want to change the Trace implementation that your program uses, you'll need to edit each class that instantiates a Trace implementation. Depending upon the number of classes that use Trace, it might take a lot of work for you to make the change. Plus, you want to avoid altering your classes as much as possible.
A factory method lets us be a lot smarter about how our classes obtain Trace implementation instances:
Listing 5
public class TraceFactory {
public static Trace getTrace() {
return new SystemTrace();
}
}
getTrace() is a factory method. Now, whenever you want to obtain a reference to a Trace, you can simply call TraceFactory.getTrace():
Listing 6
//... some code ...
Trace log = new TraceFactory.getTrace();
//... code ...
log.debug( "entering loog" );
// ... etc ...
Using a factory method to obtain an instance can save you a lot of work later. In the code above, TraceFactory returns SystemTrace instances. Imagine again that your requirements change and that you need to write your messages out to a file. However, if you use a factory method to obtain your instance, you need to make only one change in one class in order to meet the new requirements. You do not need to make changes in every class that uses Trace. Instead you can simply redefine getTrace():
Listing 7
public class TraceFactory {
public static Trace getTrace() {
try {
return new FileTrace();
} catch ( java.io.IOException ex ) {
Trace t = new SystemTrace();
t.error( "could not instantiate FileTrace: " + ex.getMessage() );
return t;
}
}
}
Further, factory methods prove useful when you're not sure what concrete implementation of a class to instantiate. Instead, you can leave those details to the factory method.
In the above examples your program didn't know whether to create FileTrace or SystemTrace instances. Instead, you can program your objects to simply use Trace and leave the instantiation of the concrete implementation to a factory method.
About the author
Tony Sintes is a principal consultant at BroadVision. A Sun-certified Java 1.1 programmer and Java 2 developer, he has worked with Java since 1997.
Wednesday, July 20, 2011
Implementing Callback in Java
interface InterestingEvent {
// This is just a regular method so it can return something or
// take arguments if you like.
public void interestingEvent ();
}
class CallMe implements InterestingEvent {
public CallMe ()
{
// en = new EventNotifier (this);
}
// Define the actual handler for the event.
public void interestingEvent ()
{
System.out.println("Wow! Something really interesting must have occurred!");
// Do something...
}
//...
}
class EventNotifier {
private InterestingEvent ie;
private boolean somethingHappened;
public EventNotifier (InterestingEvent event)
{
// Save the event object for later use.
ie = event;
// Nothing to report yet.
somethingHappened = false;
}
//...
public void doWork ()
{
somethingHappened = true;
// Check the predicate, which is set elsewhere.
if (somethingHappened)
{
// Signal the even by invoking the interface's method.
ie.interestingEvent ();
}
//...
}
// ...
}
public class TestCallback {
public static void main(String[] args) {
CallMe me = new CallMe();
EventNotifier event = new EventNotifier(me);
event.doWork();
}
}
Source: href="http://www.javaworld.com/javaworld/javatips/jw-javatip10.html
Sunday, July 17, 2011
Array of Pointers
A pointer can only point to a single object such as char and int; whereas an array of pointers can point to several objects. For example,
// void printName(char *p[])
// void printName(char *p[])
void printName(char **p)
{
printf("Name1: %s\n", p[0]);
printf("Name2: %s\n", p[1]);
}
int main(int argc, char *argv[])
{
char name1[] = "Name 1";
char name2[] = "Name 2";
char *p[2];
p[0] = name1;
p[1] = name2;
printName(p);
}
Monday, May 02, 2011
Simple File Input
Simple File Input
C++ programs can read and write files in many ways. For the sake of simplicity and uniformity, files are read and written using the same stream method already introduced for keyboard input. For this page, we first need a test data file with known contents. Please compile and run the following program:
#include
#include
using namespace std;
int main()
{
ofstream ofs("data.txt");
for(int i =1;i <= 10;i++) {
ofs << "This is line " << i << endl;
}
return 0;
}
If you want to see what this program's output is, simply examine the contents of the file "data.txt" that this program creates when run. Not visible in the output file are some "control characters." A "control character" is a character that, instead of printing a symbol, causes an action to take place, like moving down to the next line on the display. A regular character is simply printed. A control character causes an action. Here are some common control characters, their symbols, and what they do: | Linefeed | '\n' | Causes the printing position to move to a new line |
| Tab | '\t' | Causes the printing position to advance to a fixed column |
| Bell | '\a' | Causes a bell to ring (most platforms) |
cout << "This is a test line\n\n";
This example will print a line followed by two linefeeds, which assures one blank line appears before the next line is printed. Q: If I can add "\n" to the text of my printed lines, why use the special operator "endl" as in the example above? The operator "endl" does two things. It (1) causes a newline to be printed, and it (2) causes the output to appear immediately.In C++, input and output streams are "buffered." This means characters are read and written in groups, for the sake of efficiency. When keyboard input is being accepted, an entire line is read at once, which is why the user must press "Enter" to move along. When program data is being written, it is normally emitted in chunks. To force output to be emitted at a particular time, either use "endl" as in the above example, or do this:
cout << "This will appear right away." << flush;
The operator "flush" causes immediate output, which means these two lines are equivalent:
cout << endl;
cout << "\n" << flush;
Now let's read our data file in an obvious way — line by line. The following program contains the single most common student error in file reading. See if you can spot what the error is, what mistake it creates, and why. To reduce any chance for confusion, the error is in red :
#include
#include
#include
using namespace std;
// this program contains an error
int main()
{
ifstream ifs("data.txt");
string line;
// error in stream test
while(!ifs.eof()) {
getline(ifs,line); cout << "[ " << line << " ]" << endl;
}
return 0;
}
When you run this program, you will see a blank line is printed after the last valid data line. This is caused by the program error. The error is attempting to test the stream for "end-of-file" without also trying to read it:
while(!ifs.eof()) {
Remember: a C++ stream can have any origin — a file, a network connection, a keyboard, or any other source. Therefore the stream cannot detect that the data has ended until a read attempt fails. Because of this, a program that tests for end-of-file without reading, then reads without testing, always fails. A successful program always tests and reads at once. Here is a corrected version of the program:
#include
#include
#include
using namespace std;
int main()
{
ifstream ifs("data.txt");
string line;
while(getline(ifs,line)) {
cout << "[ " << line << " ]" << endl;
}
return 0;
}
In the next example, we will use the stream extraction operator ">>" to read our file. Compile and run this program (it also has an error ):
#include
#include
#include
using namespace std;
int main()
{
ifstream ifs("data.txt");
string word1, word2, word3;
int num;
while(ifs >> word1 >> word2 >> word3 >> num) {
cout << "[ "
<< word1
<< word2
<< word3
<< num
<< " ]"
<< endl;
}
return 0;
}
Why does the error cause the output to look all squeezed together? To answer this question, we need to look at how the stream extraction operator ">>" works. The extraction operator is actually a very sophisticated tool. It knows what kind of variable is receiving the data, and it conducts itself accordingly. It works like this: - Phase 1 (search):
- Read characters.
- If a character is "whitespace" (control characters or spaces), discard it.
- If a non-whitespace character appears that is not appropriate to the target variable, stop, indicate an error, "break" the stream.
- If a character is appropriate to the target variable --
- For integer variables, any of "+-0123456789".
- For float/double variables, any of "+-.0123456789e" in a prescribed order.
- For string variables, any non-whitespace characters.
- Phase 2 (read):
- Read and accept characters that are appropriate to the target variable.
- If a character appears that is not appropriate to the target variable, either whitespace or some other character, don't discard it, stop reading, no error.
#include
#include
#include
using namespace std;
int main()
{
ifstream ifs("data.txt");
string word1, word2, word3, line;
int num;
// read a line using the extraction operator
if(ifs >> word1 >> word2 >> word3 >> num) {
cout << "[ "
<< word1 << ' '
<< word2 << ' '
<< word3 << ' '
<< num << " ]"
<< endl;
}
// read a line using getline
if(getline(ifs,line)) {
cout << "[" << line << "]" << endl;
} return 0;
}
Why does this program fail — why can't it read the file's second line? Think: - In Phase 2, the extraction operator reads characters until it encounters whitespace, then it stops without discarding any of the whitespace.
- getline() only reads until it encounters a linefeed.
#include
#include
#include
using namespace std;
int main()
{
ifstream ifs("data.txt");
string word1, word2, word3, line;
int num;
// read a line using the extraction operator
if(ifs >> word1 >> word2 >> word3 >> num) {
cout << "[ "
<< word1 << ' '
<< word2 << ' '
<< word3 << ' '
<< num << " ]"
<< endl;
} // discard whitespace
ifs.ignore(10000,'\n');
// read a line using getline
if(getline(ifs,line)) {
cout << "[ " << line << " ]" << endl;
} return 0;
}
Source: http://www.arachnoid.com/cpptutor/student2.html
Thursday, March 17, 2011
Perl: BEGIN and END
| Perl Script | Output |
|---|---|
BEGIN { print "Birth of a process...\n"; } print "Life of a process...\n"; die "Murder of a process...\n"; END { print "Death of a process...\n"; } | Birth of a process... Life of a process... Murder of a process... Death of a process... bash-2.03$ bash-2.03$ |
| Perl Script | Output |
BEGIN { print "Birth still runs !\n"; } This won't compile; END { print "Death still runs !\n"; } | Birth still runs ! Can't locate object method "This" via package "won::t" (perhaps you forgot to load "won::t"?) at 1.pl line 5. Death still runs ! |
| Perl Script | Output |
die "Bye"; END { print "End 1\n" } BEGIN { print "Begin 1\n"; } END { print "End 2\n" } BEGIN { print "Begin 2\n"; } | Begin 1 Begin 2 Bye at 1.pl line 1. End 2 End 1 |
BEGIN
Run some code as soon as it has all been read in by the parser and before the rest compiles.
END
Run some code as late as possible. When the interpreter is ready to shut down.
Monday, March 14, 2011
How to implement callback functions in Java?
The
callback function is excutable code that is called through a function pointer. You pass a callback function pointer as an argument to other code, or register callback function pointer in somewhere. When something happens, the callback function is invoked.C/C++ allow function pointers as arguments to other functions but there are no pointers in Java. In Java, only objects and primitive data types can be passed to methods of a class. Java's support of interfaces provides a mechanism by which we can get the equivalent of callbacks. You should declare an interface which declares the function you want to pass.
The
collections.sort(List list, Comparator c) is an example of implementing callback function in Java. The c is an instance of a class which implements compare(e1, e2)method in the Comparator interface. It sorts the specified list according to the order induced by the specified comparator. All elements in the list must be mutually comparable using the specified comparator.Use
inner classes to define an anonymous callback class, instantiate an anonymous callback delegate object, and pass it as a parameter all in one line. One of the common usage for inner classes is to implement interfaces in event handling.class SomePanel extends JPanel {
private JButton myGreetingButton = new JButton("Hello");
private JTextField myGreetingField = new JTextField(20);
private ActionListener doGreeting = new ActionListener {
public void actionPerformed(ActionEvent e) {
myGreetingField.setText("Hello");
}
};
public SomePanel() {
myGreetingButton.addActionListener(doGreeting);
// . . . Layout the panel.
}
}Source: http://www.xyzws.com/javafaq/how-to-implement-callback-functions-in-java/157
Wednesday, October 20, 2010
UCM with SVN
This article describes how to apply UCM with the SVNVCS.
Contents
- Introduction
- About VCS
- About ITS
- About UCM
- About SVN
- How to perform UCM using SVN
- Projects
- Streams
- Components
- Issue Tracking
Introduction
Proper change tracking and version control is vital for the success of any software project. This article describes the UCM approach to change control and how to implement it using SVN.
About VCS
Version Control Systems are vital for the success of any software project. Programmers must have possibilities to experiment with new ideas without impacting other team members and general development. Changes should be thoroughly tested before they are delivered to a common code base. It must be possible to see when and by whome each change to the software was introduced.
More elaborate environments require even more. Different variants of a product must be developed independently of each other. For instance, while one subteam is preparing the current code for a release and polishes away the last known bugs, another team at the same time continues development for a new version. Changes by the development team shouldn't affect the release team.
A relatively new approach requires that different variants of a product are made up of different components, which are tracked individually by the version control system. This is component based version control.
About ITS
Issue Tracking Systems, also known as Bugtrackers or Change Request Managers (there are slight differences between these terms which are out of scope of this document), allow developers and other participants in projects, like project managers, trackers, testers and quality assurance, to track the state about issues like open bugs or requested features.
About UCM
Unified Change Management is a relatively young approach to version control. It's main attributes are:
- Stream-oriented development and integration
- Activities
- Component oriented version control
- Close coupling with an issue tracking system
UCM gained much popularity in the context of IBM Rational ClearCase UCM, which is an extension of ClearCase to support the UCM approach of version control.
About SVN
Subversion is a light-weight VCS meant to replace CVS. CVS was the most popular VCS in open source development for a very long period of time. CVS is very easy to handle and for a version control system easy to understand. Besides that CVS also is extremely fast, in LAN environments as well as in WAN environments. Even over the Internet, CVS is very fast.
As a replacement for CVS, SVN is meant to provide all positive features of CVS as well as several new features. Apart from being more modern in supporting versioning of directories and file attributes, SVN provides three main attributes / advantages over CVS which also significantly differ SVN from most other VCS:
- Versions are applied to the repository, not single files or directories.
- This makes it extremely easy to identify all matching files and directories for a specific version of a particular file.
- SVN has cheap copies.
- The cheap copy mechanism replaces previous mechanisms for branching, tagging or labelling. A cheap copy is a copy of a whole directory tree made inside the repository. Branches, tags and labels are implemented using these cheap copies. The cheap copies are named cheap because creating a cheap copy is an operation with very very little overhead. It's nothing else like "I'm a copy of path/to/foo revision n". This also means that in SVN, attributes like branches, labels or tags merely are directories. This leaves much individual flexibility on how to organize version management to the projects, they can adapt it on their needs.
svn:externalssvn:externalsis a property which allows to link to other repositories or other locations in the same repository.
How UCM works in general
First of all, development is no longer parted in a main branch plus lots of changes to it, but changes are grouped in multiple ways. All changes that together make up a single feature or bug fix or similar group are grouped as "activity". An activity appears as issue item in the issue tracker, that means an activity is associated with an issue tracker item and vice versa. Activities are performed on a development stream, which is a copy of the integration stream, and then "delivered" (merged) into that integration stream.
Original UCM concepts
This subchapter describes the original UCM concepts as they were applied in ClearCase UCM. The goal is to be able to apply UCM with any version control system, particularly Subversion. For that, it is necessary to understand the intentions of UCM and its concepts, and why it is implemented in ClearCase the way it is.
ClearCase limitations
ClearCase is a very old-fashioned version control system. Basically ClearCase is RCS with improved multi-user and directory support, a network file system (as if there weren't already enough of them) and database backend. The elementary concepts staid the same over time. That means:
- Revisions are done on a per-element basis.
- There is no low-level support for atomic changesets.
- Conflicts are prevent with locking (reserved checkout).
ClearCase UCM is built on top of ClearCase. ClearCase UCM has to take into account these limitations and live with them. ClearCase UCM has to hide these limitations.
ClearCase UCM glossary
- Activity
- An activity is a group of changes that belong together. Purpose:
- They link changes together, putting single checkout / checkin operations into the context of a group called Activity.
- They link changes with an issue tracker.
- Baseline
- A baseline is a consistent version state of a component. Purpose:
- Keep those revisions of files and directories together which belong together.
- Component
- A component is a group of files and directories which are managable as single unit to be baselined. Purpose:
- Keep those files and directories together which belong together.
- Composite baseline
- A composite baseline is the combination of multiple baselines from several components. Usually, a project has a composite baseline which sums up the baselines for all participating components. Purpose:
- Keep those revisions of components in a project together which belong together.
- Delivery
- Delivery is the operation of merging changes from a child Stream to a parent Stream (usually the Integration Stream). Purpose:
- Perform merges on groups of files and directories instead of single files and directories.
- Keep changesets together.
- Integration Stream
- An Integration Stream is a Stream with child streams. For a Project, at least one Stream exists, which is its Integration Stream. Purpose:
- Have a branch on which all changes that are mature enough are available.
- Project
- A Project is a configuration of an Integration Stream and participating components in specific baselines. A project is configured by a composite baseline. Purpose:
- Prevent conflicts between different development goals of different projects.
- Allow the selection of components from a pool.
- Rebase
- Rebase is the operation of copying changes from a parent Stream (usually the Integration Stream) to a child Stream. Purpose:
- Perform merges on groups of files and directories instead of single files and directories.
- Keep changesets together.
- Stream
- A Stream is an isolated branch of development. Unless it is an integration Stream, a Stream always has a parent. Activities will only affect the stream for which they were performed. Streams are actively synchronized with each other by explicit Delivery and Rebase operations. Purpose:
- Allow changes under version control but in a controlled manner.
- Keep changesets together.
Putting UCM on a more abstract level
Many of the concepts which ClearCase UCM puts on top of ClearCase are only explicitely necessary to cope with the limitations of ClearCase. To be able to apply UCM with any version control system, it is necessary to understand the intentions of UCM and its concepts, and why it is implemented in ClearCase the way it is.
Goals on an abstract level:
- Developers shall be able to perform changes without interfering with other developers.
- Changes shall be controlled and tracked.
- Projects shall be setup in a way that they are built on reusable components.
- The reusable components shall be setup in a way that allows changing them without interfering with other projects.
Simple mapping UCM between ClearCase UCM and Subversion
For most of what is done with ClearCase UCM, the following simple mapping may already be sufficient.
| Goal | ClearCase UCM | Subversion |
|---|---|---|
| Atomic changesets (small changes) | Activity | commit |
| Atomic changesets (large changes) | Activity | directory copy, merge |
| Consistent revisions | Baseline | implicit (path + repository revision) |
| Reusable file group | Component | directory copy |
| Consistent project version | Composite baseline | implicit (path + repository revision) |
| Integrate developer work (small change) | Delivery | commit |
| Integrate developer work (large change) | Delivery | merge --reintegrate |
| Mature main branch | Integration Stream | implicit (e.g. policy for trunk) |
| Consistent overall setup | Project | directory |
| Up-to-date developer copy (small change) | Rebase | update |
| Up-to-date developer copy (large change) | Rebase | merge |
| Create place for independent developer work (small change) | create Stream | checkout |
| Create place for independent developer work (large change) | create Stream | directory copy |
Just like having no concept of tags and labels, or branches, Subversion has no concept projects, components, streams and activities. Actually, that's good news. The concept of Subversion is to work with cheap copies. Originally, cheap copies were designed to be the Subversion approach to tagging and branching. Interestingly, the more abstract approach of cheap copies is not only a simple yet superior way to resemble tags and labels, and branches. It also is a simple way to resemble projects, components, streams and activities.
At this point, let me also have a word on whether you should have one large repository or multiple small repositories. Subversion is significantly faster than ClearCase. And because commits are path-based, it can use path-based transaction isolation. That means multiple proceses can safely work on the same repository at the same time. They will only delay each other if they affect the same path.
Also, projects like KDE show that it's possible to use Subversion for very large development projects with large development teams. At the time of this writing, the KDE subversion repository was at revision 969346.
How to perform UCM using ClearCase
As already mentioned above, there's a special version of ClearCase called ClearCase UCM. When applying UCM with ClearCase, you'll notice the following things:
- Working with ClearCase when the server is offline is near impossible.
- Dynamic views don't work with the server being offline.
- Snapshot views work with the server being offline, but this is very limited. Even restoring a file to its original version requires server access.
- VOB symbolic links don't work properly with snapshot views.
- Over WANs / Internet and VPNs, ClearCase is awfully slow.
- When you're working on your own stream anyway, you'll begin to ask yourself why this obsolete checkin / checkout locking mechanism is still required.
- ClearCase will create new file revisions of all files you've touched, even if you don't actively create new versions. A file, once touched, will grow new versions for every rebase you perform.
- Activities are somehow lost once they're integrated. They are visible on the development stream but they don't become visible on the integration stream. Instead, Deliveries and Rebases appear as separate activities. The faster the development process, the higher the percentage of these artificial pseudo-activities compared to real development activities.
How to perform UCM using SVN
Most of the UCM concepts can be provided by directories and cheap copies in SVN: projects, components, streams and, if you want to, activities. That means the implementation of UCM on top of Subversion is very flexible. It requires only little discipline, so no additional scripts should be required. Also, subversion is much more likely to forgive errors or mistakes in the setup. And it's easy to restructure the repository afterwards, so you can even turn a non-UCM-repository into a UCM-repository.
The flexibility of Subversion also means that the following is just one out of many possible ways to implement UCM on top of Subversion.
Original Subversion approach: TTB
/trunk/tags/branches/
This is the original subversion approach, also known as
TTB structure. It already has a lot in common with UCM. Small development activities are separated by commits, large development activities can be performed on separate branches.
Single project / component approach
/trunk/tags/branches/streams/(← This is new compared to the classical approach in subversion)
This is a slightly modified approach, which I call
TTBS(you guessed ;-). It separates streams / developer branches from (release) branches.
Distinct Multi-Project approach
/- projectname
trunk/tags/branches/streams/(← This is new compared to the classical approach in subversion)
- projectname
Often, multiple projects shall be supported in the same repository. For that, it is a good idea (and common practice) to have the projects on top level and the TTB(S) structure below that.
If your component model works on mature objects only, which is the case for many Java projects, this is enough: If one project depends on the other, it waits for a release (.jar, .war, .ear or so).
However, in some development environments, it takes days or even weeks for a project to make a release for just one minor change. In such an environment, if project A depends on project B, project A might be better off with a copy of project B. That's the next approach.
Establish Reuse
Reuse means to have something available which was created elsewhere. For reuse, subversion offers two possibilities, both of which work fine on directories (and single files, if wanted):
- cheap copies
- svn:externals
If you want to reuse something in an unchanged form, the best way of doing that is using
svn:externals. If you want to change it, the best way of doing that is using cheap copies (svn cp).Separate component / project approach
/projects/- projectname
trunk/tags/branches/streams/
- projectname
components/- componentname
trunk/tags/branches/streams/
- componentname
A component can be made visible anywhere within a project, either as cheap copy or as external.
How to apply UCM to SVN - The Commands
Creating a Project or Component
As a project or component is just a directory, it's created like trunk: Create the directory, if you start from scratch, or import something that you already have.
Creating a Stream
To create a Stream, create a copy from what you want to create a stream for, and place that copy in streams/.
Synopsis:
svn cp parentPath streams/streamNameExample stream from trunk:
svn cp -m "Creating Stream barBuzz." http://svn.mynet.local/projectFoo/trunk http://svn.mynet.local/projectFoo/streams/barBuzzRebasing a Stream
Starting with Subversion 1.5, rebasing a stream becomes very simple. Use the
svn merge command for that.Synopsis:
svn merge parentPathExample:
cd barBuzz; svn merge http://svn.mynet.local/projectFoo/trunkDelivering a Stream
First you rebase your stream to make sure you deliver a consistent set. Then you go to trunk and deliver using the
svn merge --reintegrate command.Synopsis:
cd parentPath ; svn merge --reintegrate streams/streamNameExample:
cd ../../trunk ; svn merge --reintegrate http://svn.mynet.local/projectFoo/streams/barBuzzOnce the deliver merge is done, check the delivery and if everything is okay, complete it by performing a commit.
As soon as the delivery is done, the stream should be removed. It is neither possible nor desired from a subversion point of view to reuse a stream once a delivery is done. If you want to continue working on that stream after the delivery, like some developers do in ClearCase UCM, just recreate the stream after deleting it.
Removing a Stream
To remove a stream, simply delete the stream like a normal directory. Removing a stream will not reduce the server load, it will just make the stream invisible, nothing more.
Example
This chapter describes an example of how development could work, and it also shows how a subversion repository can be transformed to the different parts of UCM as needed.
The beginning is an application called "JEduca", an application for creating and running tests based on multiple choice questions. The developers are Alice, Bob and Charly.
Alice creates a repository for them:
svnadmin create /home/alice/svnroot
The developers that begin to work on JEduca, execute:
mkdir ~/svn cd ~/svn svn checkout file:///home/alice/svnroot JEduca
Whenever they want to access changes that the others made, they perform a rebase:
svn up
Whenever they have finished an activity, they perform a delivery:
svn commit -m "Activity description."
After a few days, Alice and Bob want to create the first release, while Charly wants to continue working on new features. They decide it's time for a branch. Prior to branching they have to perform a small change to the repository and make it ready for branches: Bob executes:
files=$(echo *) svn mkdir trunk tags branches svn mv $files trunk/ svn commit -m "Created TTB structure."
The sandboxes now have should be relocated to trunk, because the position of trunk has virtually changed.
Now that the repository is raedy for branches, Bob creates the branch for the 0.1 release:
svn cp -m "Create release branch for 0.1." file:///home/alice/svnroot/trunk file:///home/alice/svnroot/branches/0.1
The story continues with the next update.
Friday, October 15, 2010
Multi-dimensional Arrays in PERL
Since the advent of reference data type in PERL, it is now relatively easy to create multi-dimensional arrays.
Each element in an array must be scalar. Therefore, the following array is NOT an 2-D array, but actually is a 1-D array.
Reference is actually a scalar that points to another data including an array. For example, $ref1 is a reference that points to an array. $ref2 is also a reference that points to another array.
Now to construct a 2-D array, we can use those two references as follows.
Or as a short cut, we could have used anonymous references. That is, we didn't need to explicitly declare the references before using them such as this.
To read an element in the 2-D array, we use subscripts:
will print the content of the first element in the first array, which is 1.
will print the content of the third element in the first array, which is 3.
will print the content of the third element in the second array, which is 6.
We can explore further by creating 3-D array.
For example,
Each element in an array must be scalar. Therefore, the following array is NOT an 2-D array, but actually is a 1-D array.
@onedarray = ((1,2,3),(4,5,6));which is the same as @onedarray = (1,2,3,4,5,6);
Reference is actually a scalar that points to another data including an array. For example, $ref1 is a reference that points to an array. $ref2 is also a reference that points to another array.
$ref1 = [1,2,3];
$ref2 = [4,5,6];
Now to construct a 2-D array, we can use those two references as follows.
@twodarray = ($ref1,$ref2);
Or as a short cut, we could have used anonymous references. That is, we didn't need to explicitly declare the references before using them such as this.
@twodarray = ([1,2,3],[4,5,6]);
To read an element in the 2-D array, we use subscripts:
print $twodarray[0][0];
will print the content of the first element in the first array, which is 1.
print $twodarray[0][2];
will print the content of the third element in the first array, which is 3.
print $twodarray[1][2];
will print the content of the third element in the second array, which is 6.
We can explore further by creating 3-D array.
For example,
@threedarray = ([[1,2,3],[4,5,6]],[[7,8,9],[10,11,12]]);will print 6.
print $threedarray[0][1][2];
Thursday, June 24, 2010
Character Pointers and Functions
page 104
Since text strings are represented in C by arrays of characters, and since arrays are very often manipulated via pointers, character pointers are probably the most common pointers in C.
Deep sentence:
At the bottom of the page is a very important picture. We've said that pointers and arrays are different, and here's another illustration. Make sure you appreciate the significance of this picture: it's probably the most basic illustration of how arrays and pointers are implemented in C.
We also need to understand the two different ways that string literals like "now is the time" are used in C. In the definition
As an example of what we can and can't do, given the lines
Deep sentence:
page 105
Once again, these code fragments are being written in a rather compressed way. To make it easier to see what's going on, here are alternate versions of strcpy, which don't bury the assignment in the loop test. First we'll use array notation:
Here is a similar function, using pointer notation:
All of these versions of strcpy are quite similar to the copy function we saw on page 29 in section 1.9.
page 106
The version of strcpy at the top of this page is my least favorite example in the whole book. Yes, many experienced C programmers would write strcpy this way, and yes, you'll eventually need to be able to read and decipher code like this, but my own recommendation against this kind of cryptic code is strong enough that I'd rather not show this example yet, if at all.
We need strcmp for about the same reason we need strcpy. Just as we cannot assign one string to another using =, we cannot compare two strings using ==. (If we try to use ==, all we'll compare is the two pointers. If the pointers are equal, they point to the same place, so they certainly point to the same string, but if we have two strings in two different parts of memory, pointers to them will always compare different even if the strings pointed to contain identical sequences of characters.)
Note that strcmp returns a positive number if s is greater than t, a negative number if s is less than t, and zero if s compares equal to t. ``Greater than'' and ``less than'' are interpreted based on the relative values of the characters in the machine's character set. This means that 'a' < 'b', but (in the ASCII character set, at least) it also means that 'B' < 'a'. (In other words, capital letters will sort before lower-case letters.) The positive or negative number which strcmp returns is, in this implementation at least, actually the difference between the values of the first two characters that differ.
Note that strcmp returns 0 when the strings are equal. Therefore, the condition
To continue our ongoing discussion of which pointer manipulations are safe and which are risky or must be done with care, let's consider character pointers. As we've mentioned, one thing to beware of is that a pointer derived from a string literal, as in
For the above reasons, all three of these examples are incorrect:
page 106 continued (bottom)
Expressions like *p++ and *--p may seem cryptic at first sight, but they're actually analogous to array subscript expressions like a[i++] and a[--i], some of which we were using back on page 47 in section 2.8.
http://www.eskimo.com/~scs/cclass/krnotes/sx8e.html
Since text strings are represented in C by arrays of characters, and since arrays are very often manipulated via pointers, character pointers are probably the most common pointers in C.
Deep sentence:
C does not provide any operators for processing an entire string of characters as a unit.We've said this sort of thing before, and it's a general statement which is true of all arrays. Make sure you understand that in the lines
char *pmessage; pmessage = "now is the time"; pmessage = "hello, world";all we're doing is assigning two pointers, not copying two entire strings.
At the bottom of the page is a very important picture. We've said that pointers and arrays are different, and here's another illustration. Make sure you appreciate the significance of this picture: it's probably the most basic illustration of how arrays and pointers are implemented in C.
We also need to understand the two different ways that string literals like "now is the time" are used in C. In the definition
char amessage[] = "now is the time";the string literal is used as the initializer for the array amessage. amessage is here an array of 16 characters, which we may later overwrite with other characters if we wish. The string literal merely sets the initial contents of the array. In the definition
char *pmessage = "now is the time";on the other hand, the string literal is used to create a little block of characters somewhere in memory which the pointer pmessage is initialized to point to. We may reassign pmessage to point somewhere else, but as long as it points to the string literal, we can't modify the characters it points to.
As an example of what we can and can't do, given the lines
char amessage[] = "now is the time"; char *pmessage = "now is the time";we could say
amessage[0] = 'N';to make amessage say "Now is the time". But if we tried to do
pmessage[0] = 'N';(which, as you may recall, is equivalent to *pmessage = 'N'), it would not necessarily work; we're not allowed to modify that string. (One reason is that the compiler might have placed the ``little block of characters'' in read-only memory. Another reason is that if we had written
char *pmessage = "now is the time"; char *qmessage = "now is the time";the compiler might have used the same little block of memory to initialize both pointers, and we wouldn't want a change to one to alter the other.)
Deep sentence:
The first function is strcpy(s,t), which copies the string t to the string s. It would be nice just to say s=t but this copies the pointer, not the characters.This is a restatement of what we said above, and a reminder of why we'll need a function, strcpy, to copy whole strings.
page 105
Once again, these code fragments are being written in a rather compressed way. To make it easier to see what's going on, here are alternate versions of strcpy, which don't bury the assignment in the loop test. First we'll use array notation:
void strcpy(char s[], char t[])
{
int i;
for(i = 0; t[i] != '\0'; i++)
s[i] = t[i];
s[i] = '\0';
}
Note that we have to manually append the '\0' to s after the loop. Note that in doing so we depend upon i retaining its final value after the loop, but this is guaranteed in C, as we learned in Chapter 3.Here is a similar function, using pointer notation:
void strcpy(char *s, char *t)
{
while(*t != '\0')
*s++ = *t++;
*s = '\0';
}
Again, we have to manually append the '\0'. Yet another option might be to use a do/while loop.All of these versions of strcpy are quite similar to the copy function we saw on page 29 in section 1.9.
page 106
The version of strcpy at the top of this page is my least favorite example in the whole book. Yes, many experienced C programmers would write strcpy this way, and yes, you'll eventually need to be able to read and decipher code like this, but my own recommendation against this kind of cryptic code is strong enough that I'd rather not show this example yet, if at all.
We need strcmp for about the same reason we need strcpy. Just as we cannot assign one string to another using =, we cannot compare two strings using ==. (If we try to use ==, all we'll compare is the two pointers. If the pointers are equal, they point to the same place, so they certainly point to the same string, but if we have two strings in two different parts of memory, pointers to them will always compare different even if the strings pointed to contain identical sequences of characters.)
Note that strcmp returns a positive number if s is greater than t, a negative number if s is less than t, and zero if s compares equal to t. ``Greater than'' and ``less than'' are interpreted based on the relative values of the characters in the machine's character set. This means that 'a' < 'b', but (in the ASCII character set, at least) it also means that 'B' < 'a'. (In other words, capital letters will sort before lower-case letters.) The positive or negative number which strcmp returns is, in this implementation at least, actually the difference between the values of the first two characters that differ.
Note that strcmp returns 0 when the strings are equal. Therefore, the condition
if(strcmp(a, b)) do something...doesn't do what you probably think it does. Remember that C considers zero to be ``false'' and nonzero to be ``true,'' so this code does something if the strings a and b are unequal. If you want to do something if two strings are equal, use code like
if(strcmp(a, b) == 0) do something...(There's nothing fancy going on here: strcmp returns 0 when the two strings are equal, so that's what we explicitly test for.)
To continue our ongoing discussion of which pointer manipulations are safe and which are risky or must be done with care, let's consider character pointers. As we've mentioned, one thing to beware of is that a pointer derived from a string literal, as in
char *pmessage = "now is the time";is usable but not writable (that is, the characters pointed to are not writable.) Another thing to be careful of is that any time you copy strings, using strcpy or some other method, you must be sure that the destination string is a writable array with enough space for the string you're writing. Remember, too, that the space you need is the number of characters in the string you're copying, plus one for the terminating '\0'.
For the above reasons, all three of these examples are incorrect:
char *p1 = "Hello, world!"; char *p2; strcpy(p2, p1); /* WRONG */
char *p = "Hello, world!"; char a[13]; strcpy(a, p); /* WRONG */
char *p3 = "Hello, world!"; char *p4 = "A string to overwrite"; strcpy(p4, p3); /* WRONG */In the first example, p2 doesn't point anywhere. In the second example, a is a writable array, but it doesn't have room for the terminating '\0'. In the third example, p4 points to memory which we're not allowed to overwrite. A correct example would be
char *p = "Hello, world!"; char a[14]; strcpy(a, p);(Another option would be to obtain some memory for the string copy, i.e. the destination for strcpy, using dynamic memory allocation, but we're not talking about that yet.)
page 106 continued (bottom)
Expressions like *p++ and *--p may seem cryptic at first sight, but they're actually analogous to array subscript expressions like a[i++] and a[--i], some of which we were using back on page 47 in section 2.8.
http://www.eskimo.com/~scs/cclass/krnotes/sx8e.html
Is a string literal in c++ created in static memory?
Where it's created is an implementation decision by the compiler writer, really. Most likely, string literals will be stored in read-only segments of memory since they never change.
In the old compiler days, you used to have static data like these literals and global but changeable data. These were stored in the TEXT (code) segment and BSS (initialized data) segment.
Even when you have code like char *x = "hello";, the hello string is stored in read-only memory while the variable x is on the stack (or writable memory at global scope). x just gets set to the address of the hello string. This allows all sorts of tricky things like string folding, so that "invalid option" (0x1000) and "valid option" (0x1002) can use the same memory block as follows:
0x1000 invalid option\0
Keep in mind I don't mean read-only memory in terms of ROM, just memory that's dedicated to storing unchangeable stuff (which may be marked really read-only by the OS).
They're also never destroyed until main() exits.
Source: http://stackoverflow.com/questions/349025/is-a-string-literal-in-c-created-in-static-memory
In the old compiler days, you used to have static data like these literals and global but changeable data. These were stored in the TEXT (code) segment and BSS (initialized data) segment.
Even when you have code like char *x = "hello";, the hello string is stored in read-only memory while the variable x is on the stack (or writable memory at global scope). x just gets set to the address of the hello string. This allows all sorts of tricky things like string folding, so that "invalid option" (0x1000) and "valid option" (0x1002) can use the same memory block as follows:
0x1000 invalid option\0
Keep in mind I don't mean read-only memory in terms of ROM, just memory that's dedicated to storing unchangeable stuff (which may be marked really read-only by the OS).
They're also never destroyed until main() exits.
Source: http://stackoverflow.com/questions/349025/is-a-string-literal-in-c-created-in-static-memory
Tuesday, June 22, 2010
Shell Loop Interaction with SSH
A flawed method to run commands on multiple systems entails a shell while loop over hostnames, and a Secure Shell (SSH) connection to each system. However, the default standard input handling of ssh drains the remaining hosts from the while loop:
#!/bin/sh
# run hostname command on systems listed below; will only work for
# the first host
while read hostname; do
ssh $hostname hostname
done <
example.com
example.org
EOF
# run hostname command on systems listed below; will only work for
# the first host
while read hostname; do
ssh $hostname hostname
done <
example.com
example.org
EOF
The hostname command will only be run on the first host connected to, as ssh will pass the remaining hostnames in the while loop to hostname as standard input. hostname ignores this input silently, and the while loop then exits, as no hosts remain to connect to.
Any command that reads from standard input will consume the rest of the items to loop over, as illustrated below using the cat command.
#!/bin/sh
while read line; do
echo "line: $line"
cat
done <
foo
bar
zot
EOF
while read line; do
echo "line: $line"
cat
done <
foo
bar
zot
EOF
The cat should print the remaining items of the loop to standard output, as by default it reads from standard input.
$ sh test
line: foo
bar
zot
line: foo
bar
zot
To avoid this problem, alter where the problematic command reads standard input from. If no standard input need be passed to the command, read standard input from the special/dev/null device:
#!/bin/sh
while read hostname; do
ssh $hostname hostname < /dev/null
done <
example.com
example.org
EOF
while read hostname; do
ssh $hostname hostname < /dev/null
done <
example.com
example.org
EOF
Another option: use the -n option to ssh, which prevents ssh from reading from standard input:
ssh -n $hostname hostname
However, sometimes standard input must be passed to the remote system, for example when listing, editing, then updating crontab(5) data. The first ssh instance disables passing standard input, while the second does not, as the updated crontab(5) data is passed via standard input over ssh:
while read hostname; do
ssh -n $hostname crontab -l | \
grep -v rdate | \
ssh $hostname crontab -
done
ssh -n $hostname crontab -l | \
grep -v rdate | \
ssh $hostname crontab -
done
On a somewhat related note, background processes on Unix should reopen standard input to/dev/null.
Alternatives & Caveats
- for loop - a common alternative, and perhaps useless use of cat, instead loops over the hostnames via for host in `cat hostlist`; …. Beware extraneous IFS related data in the file, though this should not be a concern for hostnames.
- while loops will not process the last line, if the file does not end with a newline. This is a risk if the hostname list origniates on a foreign system, or via any editor that does not enforce the traditional unix requirement that files end with a trailing newline.
$ echo -n $IFS | od -bc
0000000 040 011 012 000
\t \n \0
0000004
Source: http://sial.org/howto/shell/while-ssh/
Subscribe to:
Posts (Atom)