dotLRN provides you with a number of customization options. Where the out of the box installation does not match your requirements, dotLRN's behavior can often be changed through the OpenACS parameter system. Where dotLRN is missing a key feature area, its clean modular boundaries make it easy to develop collaborating, dotLRN-compatible modules. And in some cases, perhaps, the core dotLRN packages simply do not match your requirements. In this case, because dotLRN is free software, you can modify its source code to meet your needs.
When it comes time to add and modify files, for the sake of your sanity and productivity you should use a source code control system to manage your project's code. The Concurrent Versions System, or CVS, is a good choice. It is free, widely-used and well-documented. The rest of this document covers the details of using CVS for dotLRN development.
For the purposes of this discussion we will assume a fairly specific case, namely that
We recommend that you use CVS anyway, if only because it allows you produce a complete copy of your project code with a single shell command (useful for setting up new servers). This way, you will also be prepared to track changes to core project files if the need arises (to fix a spelling error, for example). As explained in detail below, the base project files are stored in CVS on a "vendor branch". Updates to the base project, such as new releases, are periodically committed to these branches and integrated into the main development trunk. If no changes have been made to the base files, the process is equivalent to untarring the new code over the old code, with the additional benefit that the changes are being tracked in the local repository. If the base project files have been edited, a code review and conflict resolution step will need to be undertaken to merge the two sets of changes.
The decision of whether or not to edit base project files is a matter of engineering judgement and the answer will vary depending on the project. Be aware that managing multiple, moving code branches is not for the faint of heart. To be successful you will need to have a very good understanding of CVS and a deep understanding of your project's code and its dependencies. You should allocate time for careful review and testing of merge results. If at all possible, you should consider working from QA'ed release code that you will add to but not modify.
You will prompted for a password. Hit Enter.bash-2.05$ mkdir cvs-workspace bash-2.05$ cd cvs-workspace bash-2.05$ cvs -d :pserver:anonymous@openacs.org:/cvsroot login
You can alternatively usebash-2.05$ cvs -z3 -d :pserver:anonymous@openacs.org:/cvsroot \ export -r HEAD acs-core
-r tagName for a snapshot
matching a particular tag, or -D "YYYY-MM-DD" for a
snapshot of the tree on a particular date.
You should now have an export of the openacs core in the
openacs-4 subdirectory. Now you will export the OpenACS
modules required by dotLRN (check the dotLRN install doc for an up-to-date list).
Now fetch an export of the dotLRN packages.bash-2.05$ ls openacs-4 bash-2.05$ cd openacs-4/packages bash-2.05$ cvs -z3 -d :pserver:anonymous@openacs.org:/cvsroot \ export -r HEAD acs-datetime acs-developer-support acs-events acs-mail-lite \ attachments bulk-mail calendar faq file-storage forums general-comments news \ notifications ref-timezones user-preferences
Now that you have a snapshot of OpenACS and dotLRN, you need to import it into a local CVS repository. If you haven't already, create one (may require root depending on where you want to put it).bash-2.05$ cvs -d :pserver:anonymous@dotlrn.openacs.org:/dotlrn-cvsroot login (hit enter) bash-2.05$ cvs -z3 -d :pserver:anonymous@dotlrn.openacs.org:/dotlrn-cvsroot \ export -r HEAD dotlrn-core
Now import the project.bash-2.05$ sudo cvs -d /usr/local/cvsroot init
You have just created a project calledbash-2.05$ cd .. bash-2.05$ pwd /home/aegrumet/cvs-workspace/openacs-4 bash-2.05$ cvs -d /usr/local/cvsroot import \ -m "OpenACS and dotLRN heads, 2002-06-25" \ dotlrn-backed-proj dotLRN Head_2002_06_25
dotlrn-backed-proj. The initial code was brought in with
vendor tag dotLRN and release tag
Head_2002_06_25.
The following diagram depicts the CVS version information for a hypothetical file in the import:
1.1
\_
\_
\
(1.1.1) dotLRN vendor branch
\
1.1.1.1 tags: Head_2002_06_25
By convention, version numbers 1.1 and 1.1.1.1 refer to a single,
initial version of the file. The branch number 1.1.1 does not refer
to a file at all; it is simply another name for the branch that
captures the revision number at which the branch originated. A second
branch originating at version 1.1 of the file would be numbered 1.1.2.
The project should now show up in your CVS repository.
You can now remove the export files.bash-2.05$ ls /usr/local/cvsroot CVSROOT dotlrn-backed-proj
bash-2.05$ cd .. bash-2.05$ pwd /home/aegrumet/cvs-workspace bash-2.05$ rm -rf openacs-4
bash-2.05$ cvs -d /usr/local/cvsroot co -d /web/dev dotlrn-backed-proj
Returning to our example drawing above, commits to a base project file in the local checkout are represented by versions 1.2 and 1.3 below:
| 1.1
| | \_
Your | 1.2 \_
changes | | \
V 1.3 (1.1.1) dotLRN vendor branch
\
1.1.1.1 tags: Head_2002_06_25
bash-2.05$ cvs -z3 -d :pserver:anonymous@openacs.org:/cvsroot co acs-core bash-2.05$ mv openacs-4 cvs-anon bash-2.05$ cd cvs-anon/packages bash-2.05$ cvs -z3 -d :pserver:anonymous@openacs.org:/cvsroot \ co acs-datetime acs-developer-support acs-events acs-mail-lite \ attachments bulk-mail calendar faq file-storage forums general-comments news \ notifications ref-timezones user-preferences bash-2.05$ cvs -z3 -d :pserver:anonymous@dotlrn.openacs.org:/dotlrn-cvsroot \ co dotlrn-core
Now import the tree. Note: before conducting this step, you may want to tag the tree or make a note of the date and time of day, should you need to revert the tree to its pre-import state.bash-2.05$ cd ~/cvs-workspace bash-2.05$ rm -rf openacs-4 bash-2.05$ cvs -z3 -d :pserver:anonymous@openacs.org:/cvsroot \ export -r HEAD acs-core bash-2.05$ cd openacs-4/packages bash-2.05$ cvs -z3 -d :pserver:anonymous@openacs.org:/cvsroot \ export -r HEAD acs-datetime acs-developer-support acs-events acs-mail-lite \ bulk-mail calendar faq file-storage forums general-comments news \ notifications ref-timezones user-preferences bash-2.05$ cvs -z3 -d :pserver:anonymous@dotlrn.openacs.org:/dotlrn-cvsroot \ export -r HEAD dotlrn-core
bash-2.05$ cd .. bash-2.05$ pwd /home/aegrumet/cvs-workspace/openacs-4 bash-2.05$ cvs -d /usr/local/cvsroot import \ -m "OpenACS and dotLRN heads, 2002-07-25" \ dotlrn-backed-proj dotLRN Head_2002_07_25
After the second import, the CVS structure will vary depending on the change history by you and the vendor. Here are a few likely possibilities:
1.1
| \_
1.2 \_
| \
1.3 (1.1.1) dotLRN vendor branch
\
1.1.1.1 tags: Head_2002_06_25 |
| | Vendor changes
1.1.1.2 tags: Head_2002_07_25 V
1.1
\_
\_
\
(1.1.1) dotLRN vendor branch
\
1.1.1.1 tags: Head_2002_06_25 |
| | Vendor changes
1.1.1.2 tags: Head_2002_07_25 V
1.1
| \_
1.2 \_
| \
1.3 (1.1.1) dotLRN vendor branch
\
1.1.1.1 tags: Head_2002_06_25
Head_2002_07_25
1.1
\_
\_
\
(1.1.1) dotLRN vendor branch
\
1.1.1.1 tags: Head_2002_06_25
Head_2002_07_25
1.1
\_
\_
\
(1.1.1) dotLRN vendor branch
\
1.1.1.1 tags: Head_2002_07_25
1.1
\_
\_
\
(1.1.1) dotLRN vendor branch
\
1.1.1.1 tags: Head_2002_06_25
Assuming that some of your project's files have been changed by both you and the vendor, the CVS import will return a message similar to the following:
CVS is warning you here that some of your changes conflict with the vendor's changes. To resolve the conflicts, we need to perform a merge. Instead of using cvs' suggestion above, we will use the variation from Karl Fogel's book:14 conflicts created by this import. Use the following command to help the merge: cvs -d /usr/local/cvsroot checkout -jdotLRN:yesterday -jdotLRN dotlrn-backed-proj bash-2.05$
At this point, you have a checkout with conflicts in yourbash-2.05$ cd .. bash-2.05$ pwd /home/aegrumet/cvs-workspace bash-2.05$ cvs -d /usr/local/cvsroot co -kk -j Head_2002_06_25 \ -j Head_2002_07_25 dotlrn-backed-proj
cvs-workspace directory. Before continuing on, let's
pause for a minute and think about what just happened. Because no
-r or -D option was given, CVS has checked
out the HEAD version of our code. In a bizarre twist, "HEAD" in CVS
(v1.11) appears to mean
the tip of the vendor branch (i.e. 1.1.1.x) if you haven't committed anything, otherwise the tip of the trunk (1.x).Also, according to the "double j" options, CVS has computed the changes from
Head_2002_06_25 to
Head_2002_07_25, and applied these changes to the HEAD.
You can now begin to fathom what has changed by switching to the new checkout directory and issuing the command
Here is a more detailed description of what is in the checkout directory:bash-2.05$ cvs -qn update
| Description | Prefix from cvs -qn update |
|---|---|
| File was changed by both you and the vendor (Figure 1 above) | C or M |
| File was changed by the vendor but not you (Figure 2 above) | (file won't be listed) |
| File was changed by you but not the vendor (Figure 3 above) | (file won't be listed) |
| File was changed by neither you nor the vendor (Figure 4 above) | (file won't be listed) |
| File was added by the vendor (Figure 5 above) | (file won't be listed) |
| File was not changed by you and was removed by the vendor (Figure 6 above) | R |
Pause for a moment and note that there may be a significant number of files that have changed as a result of the merge (corresponding to Figures 2, 3 and 5) but aren't listed as "modified" (C or M) by CVS.
Successful completion of the merge requires code review of all the cases listed above, but your first and foremost concern will be to resolve files changed by both you and the vendor (marked C or M). The CVS structure for these files looks like this:
You can inspect the changes to the M files using1.1 | \_ 1.2 \_ | \ 1.3 (1.1.1) dotLRN vendor branch | \ | 1.1.1.1 --- | | | delta | 1.1.1.2 --- | | | checkout<---------------
cvs
diff, which will output changes from your last checked-in
version (1.x).
To inspect changes to the C files, it is important to understand the significance of the conflict markers. The conflict markers represent changes you've made since the last import that do not match the differences applied via the j tags. The markers are inserted into files with the following format:
(adapted from the "Detecting and Resolving Conflicts" section of Karl Fogel's book).<<<<<<< (filename) local (non-vendor) changes in the main development trunk blah blah blah ======= the new changes that came from the merge blah blah blah and so on >>>>>>> (latest revision number in the repository)
Usually, resolving these conflicts will require very careful thought by someone who is intimate with the code. Furthermore, note that CVS is not particularly intelligent. It generates conflicts based on pattern-matching rules and not AI or any notion of how computer languages work. Hence it is possible (and likely) that auto-merged code in "M" files and inside conflict markers in "C" files will not be logically grouped.
To illustrate, consider the following true to life example:
line 1: <li>
2: <if @forums.new_p@><b></if>
3: <a href="@forums.url@forum-view?forum_id=@forums.forum_id@">@forums.name@</a>
4: <<<<<<< forums-portlet.adp
5: <if @forums.new_p@ eq t><img src="/doc/acs-datetime/pics/new.gif" align="absmiddle" border="0" alt="New!" align="baseline"></if>
6: =======
7: <if @forums.new_p@></b></if>
8: >>>>>>> 1.1.1.2
9: </li>
In this example, we have replaced this code
<li>
<if @forums.new_p@><b></if>
<a href="@forums.url@forum-view?forum_id=@forums.forum_id@">@forums.name@</a>
<if @forums.new_p@></b></if>
</li>
with this code
<li>
<if @forums.new_p@ eq t><img src="/doc/acs-datetime/pics/new.gif" align="absmiddle" border="0" alt="New!" align="baseline"></if>
</li>
Hence our choice is not between line 5 or line 7, as suggested by the
conflict markers, but between line 5 and lines 2+3+7. Programmer
beware.
Note from the previous point that C files can also contain
modifications that did not generate conflicts. These changes should
be inspected with cvs diff.
The last things to do are: commit your changes, and update any other checkouts.
A final note: the code merging steps described above do not address the issue of database changes. Such changes must be addressed by examining changes in the SQL data model files and determining what steps must be taken to bring an existing database into sync with the expectations of the latest code.1.1 | \_ 1.2 \_ | \ 1.3 (1.1.1) dotLRN vendor branch | \ | 1.1.1.1 | | | 1.1.1.2 | 1.4 <-- merge conflicts resolved.