Difference between revisions of "SVN"

From Pickwiki
Jump to navigationJump to search
m (link fix)
 
Line 12: Line 12:
 
* 12.May.2011 james: Handle 'DICT/' in release (flist) files.
 
* 12.May.2011 james: Handle 'DICT/' in release (flist) files.
 
* 10.Aug.2010 james: Add 'COMPILE' option to check a release before it goes out.
 
* 10.Aug.2010 james: Add 'COMPILE' option to check a release before it goes out.
* 07.Oct.2009 james: Add 'UPDATE'; only add -m if 'RequiresComment'.. IS THIS OK !?
+
* 07.Oct.2009 james: Add 'UPDATE'; only add -m if '[[RequiresComment]]'.. IS THIS OK !?
* 30.Jun.2009 james: Add 'CheckReleaseStatus' to make sure nothing was committed after
+
* 30.Jun.2009 james: Add '[[CheckReleaseStatus]]' to make sure nothing was committed after
 
*                    the Release's Revision Number.
 
*                    the Release's Revision Number.
 
* 17.Nov.2008 chrisg: Added support for CLEANUP command
 
* 17.Nov.2008 chrisg: Added support for CLEANUP command
Line 19: Line 19:
 
* 22.Apr.2008 manoj: Fixed a bug that limit the length of a new comment to the comment on  
 
* 22.Apr.2008 manoj: Fixed a bug that limit the length of a new comment to the comment on  
 
*                    line 4
 
*                    line 4
* 11.Apr.2008 jim: Use the line 4 comment for the CommitComment ONLY IF there's one item.
+
* 11.Apr.2008 jim: Use the line 4 comment for the [[CommitComment]] ONLY IF there's one item.
* 11.Feb.2008 jim: RequiresFileList = @FALSE for DELETE and STATUS; so those still work
+
* 11.Feb.2008 jim: [[RequiresFileList]] = @FALSE for DELETE and STATUS; so those still work
 
*                  if files are in SVN but not in UV.
 
*                  if files are in SVN but not in UV.
 
* 14.Jan.2008 manoj: Added DELETE
 
* 14.Jan.2008 manoj: Added DELETE
Line 34: Line 34:
 
* Ex:
 
* Ex:
 
*
 
*
*  svn commit svn+ssh://manoj@svn.docmagic.com/opt/svn/dsi/Database/Universe/trunk/dsisrc
+
*  svn commit svn+ssh://manoj@svn.docmagic.com/opt/svn/dsi[[/Database/Universe/trunk/dsisrc]]
 
*
 
*
 
* Trac Reference: http://trac/dsi/wiki/UniverseInSvn
 
* Trac Reference: http://trac/dsi/wiki/UniverseInSvn
Line 48: Line 48:
  
 
   username = GET.REALUSER( Err ) ; if Err # '' then stopm Err  ;*  Err not yet implemented anyway
 
   username = GET.REALUSER( Err ) ; if Err # '' then stopm Err  ;*  Err not yet implemented anyway
   logFile  = "log/SVN.LOG"
+
   logFile  = "log[[/SVN]].LOG"
  
   gosub ParseCommandLine
+
   gosub [[ParseCommandLine]]
   gosub PrepareSvnCommand
+
   gosub [[PrepareSvnCommand]]
  
 
   if Err # '' then
 
   if Err # '' then
     gosub DisplayErrors
+
     gosub [[DisplayErrors]]
 
   end else
 
   end else
  
     gosub ExecuteSvnCommand
+
     gosub [[ExecuteSvnCommand]]
     gosub ExecutePostSvnCommands
+
     gosub [[ExecutePostSvnCommands]]
  
 
   end
 
   end
Line 65: Line 65:
 
* =======================================================================================
 
* =======================================================================================
  
PrepareSvnCommand:
+
[[PrepareSvnCommand]]:
   RequiresFileList = @FALSE
+
   [[RequiresFileList]] = @FALSE
   RequiresComment  = @FALSE
+
   [[RequiresComment]] = @FALSE
   * Also add svnOp below (in the ShowHelp )
+
   * Also add svnOp below (in the [[ShowHelp]] )
 
   begin case
 
   begin case
     case svnOp = "COMMENTS" ; RequiresFileList = @TRUE  ;*  NOT REALLY AN SVN COMMAND BUT IT'S HANDY !
+
     case svnOp = "COMMENTS" ; [[RequiresFileList]] = @TRUE  ;*  NOT REALLY AN SVN COMMAND BUT IT'S HANDY !
     case svnOp = "BASIC"    ; RequiresFileList = @TRUE  ;*  NOT REALLY AN SVN COMMAND BUT IT'S HANDY !
+
     case svnOp = "BASIC"    ; [[RequiresFileList]] = @TRUE  ;*  NOT REALLY AN SVN COMMAND BUT IT'S HANDY !
     case svnOp = "COMPILE"  ; RequiresFileList = @TRUE  ;*  NOT REALLY AN SVN COMMAND BUT IT'S HANDY !
+
     case svnOp = "COMPILE"  ; [[RequiresFileList]] = @TRUE  ;*  NOT REALLY AN SVN COMMAND BUT IT'S HANDY !
     case svnOp = "CATALOG"  ; RequiresFileList = @TRUE  ;*  NOT REALLY AN SVN COMMAND BUT IT'S HANDY !
+
     case svnOp = "CATALOG"  ; [[RequiresFileList]] = @TRUE  ;*  NOT REALLY AN SVN COMMAND BUT IT'S HANDY !
     case svnOp = "COMMIT"  ; RequiresFileList = @TRUE  ; RequiresComment = @TRUE
+
     case svnOp = "COMMIT"  ; [[RequiresFileList]] = @TRUE  ; [[RequiresComment]] = @TRUE
     case svnOp = "ADD"      ; RequiresFileList = @TRUE
+
     case svnOp = "ADD"      ; [[RequiresFileList]] = @TRUE
     case svnOp = "UPDATE"  ; RequiresFileList = @TRUE  ;*  Is this dangerous !? Just for messed up SVN !?!
+
     case svnOp = "UPDATE"  ; [[RequiresFileList]] = @TRUE  ;*  Is this dangerous !? Just for messed up SVN !?!
     case svnOp = "DELETE"  ; RequiresFileList = @FALSE ;*  Allow delete from SVN with no UV item ?
+
     case svnOp = "DELETE"  ; [[RequiresFileList]] = @FALSE ;*  Allow delete from SVN with no UV item ?
     case svnOp = "DIFF"    ; RequiresFileList = @TRUE
+
     case svnOp = "DIFF"    ; [[RequiresFileList]] = @TRUE
     case svnOp = "INFO"    ; RequiresFileList = @TRUE
+
     case svnOp = "INFO"    ; [[RequiresFileList]] = @TRUE
     case svnOp = "LISTS"    ; RequiresFileList = @TRUE  ;*  NOT REALLY AN SVN COMMAND BUT IT'S HANDY !
+
     case svnOp = "LISTS"    ; [[RequiresFileList]] = @TRUE  ;*  NOT REALLY AN SVN COMMAND BUT IT'S HANDY !
     case svnOp = "LOG"      ; RequiresFileList = @TRUE
+
     case svnOp = "LOG"      ; [[RequiresFileList]] = @TRUE
     case svnOp = "REVERT"  ; RequiresFileList = @TRUE
+
     case svnOp = "REVERT"  ; [[RequiresFileList]] = @TRUE
     case svnOp = "PROPSET"  ; RequiresFileList = @TRUE
+
     case svnOp = "PROPSET"  ; [[RequiresFileList]] = @TRUE
 
      
 
      
       if PropertyNameAndValue = '' then  
+
       if [[PropertyNameAndValue]] = '' then  
 
         Err = svnOp:" requires -P, see help"; return
 
         Err = svnOp:" requires -P, see help"; return
 
       end else
 
       end else
         PropertyNameAndValue = EREPLACE(PropertyNameAndValue, "=", " ")
+
         [[PropertyNameAndValue]] = EREPLACE([[PropertyNameAndValue]], "=", " ")
 
       end
 
       end
  
     case svnOp = "STATUS"  ; * FileList is NOT required; but use it if it's there.
+
     case svnOp = "STATUS"  ; * [[FileList]] is NOT required; but use it if it's there.
  
       if FileList = '' then
+
       if [[FileList]] = '' then
         if FileName # '' then
+
         if [[FileName]] # '' then
           FileList = FileName
+
           [[FileList]] = [[FileName]]
 
         end else
 
         end else
           FileList = "DSI.BP DA.BP WEB.BP RMS.BP"
+
           [[FileList]] = "DSI.BP DA.BP WEB.BP RMS.BP"
 
         end
 
         end
 
       end else Verbose = @TRUE ;*  Force Verbose if you list specific items.
 
       end else Verbose = @TRUE ;*  Force Verbose if you list specific items.
       if Verbose then FileList := " -v"  ;*  Always VERBOSE (show lines NOT changed too...)
+
       if Verbose then [[FileList]] := " -v"  ;*  Always VERBOSE (show lines NOT changed too...)
       CommitComment = ''  ;*  May have been set from 'ReadRelease' ?
+
       [[CommitComment]] = ''  ;*  May have been set from '[[ReadRelease]]' ?
 
        
 
        
     case svnOp = "CLEANUP" ; FileList = FileName
+
     case svnOp = "CLEANUP" ; [[FileList]] = [[FileName]]
     case svnOp = "HELP"    ; FileList = downcase(FileName) ;*  NO options required; but may have 2nd parameter
+
     case svnOp = "HELP"    ; [[FileList]] = downcase([[FileName]]) ;*  NO options required; but may have 2nd parameter
 
     case 1
 
     case 1
 
       Err = "Invalid SVN Operation '":svnOp
 
       Err = "Invalid SVN Operation '":svnOp
 
   end case
 
   end case
  
   if FileErrs # '' then crt FileErrs ; input j
+
   if [[FileErrs]] # '' then crt [[FileErrs]] ; input j
  
   if RequiresFileList then
+
   if [[RequiresFileList]] then
     Err = FileErrs ; if Err # '' then return
+
     Err = [[FileErrs]] ; if Err # '' then return
     if FileList = '' then Err = svnOp:" requires a File and Item name" ; return
+
     if [[FileList]] = '' then Err = svnOp:" requires a File and Item name" ; return
 
   end
 
   end
  
   if RequiresComment and CommitComment = '' then
+
   if [[RequiresComment]] and [[CommitComment]] = '' then
 
     if CMD.NUM.ARGS = 3 then  ;*  Only 1 file to commit: use it's comment (Tacky ?) :
 
     if CMD.NUM.ARGS = 3 then  ;*  Only 1 file to commit: use it's comment (Tacky ?) :
       FileName = CMD.ARG.S<1, 2>
+
       [[FileName]] = CMD.ARG.S<1, 2>
       ItemID  = CMD.ARG.S<1, 3>
+
       [[ItemID]]   = CMD.ARG.S<1, 3>
       open FileName to File then
+
       open [[FileName]] to File then
         read ProgramItem from File, ItemID then
+
         read [[ProgramItem]] from File, [[ItemID]] then
           CommentLine = ProgramItem<4>
+
           [[CommentLine]] = [[ProgramItem]]<4>
           CommentUser = field( CommentLine, ' ', 3 )
+
           [[CommentUser]] = field( [[CommentLine]], ' ', 3 )
           CommitComment = CommentLine[ col2() + 1, 999 ]
+
           [[CommitComment]] = [[CommentLine]][ col2() + 1, 999 ]
         end else CommitComment = ""  ;*  Why would this be ? Throw an error ?
+
         end else [[CommitComment]] = ""  ;*  Why would this be ? Throw an error ?
 
       end
 
       end
 
     end
 
     end
     gosub GetCommitComment
+
     gosub [[GetCommitComment]]
     if CommitComment = "" then Err = "Cannot ":svnOp:" with an empty comment"
+
     if [[CommitComment]] = "" then Err = "Cannot ":svnOp:" with an empty comment"
 
   end
 
   end
 
return
 
return
  
ExecuteSvnCommand:
+
[[ExecuteSvnCommand]]:
 
   *  Force the username by passing to the "sudo" command below
 
   *  Force the username by passing to the "sudo" command below
   svnCommand = SVN$CMD:' ':downcase(svnOp):' ':PropertyNameAndValue:' ':FileList
+
   svnCommand = SVN$CMD:' ':downcase(svnOp):' ':[[PropertyNameAndValue]]:' ':[[FileList]]
   if RequiresComment and CommitComment # '' then
+
   if [[RequiresComment]] and [[CommitComment]] # '' then
     svnCommand := ' -m "':CommitComment:'"'
+
     svnCommand := ' -m "':[[CommitComment]]:'"'
 
   end
 
   end
  
Line 146: Line 146:
 
       crt " (comments are always from the CURRENT version...)"
 
       crt " (comments are always from the CURRENT version...)"
 
       crt
 
       crt
       FileList = trim( FileList )
+
       [[FileList]] = trim( [[FileList]] )
       NumFiles = dcount(FileList, ' ')
+
       [[NumFiles]] = dcount([[FileList]], ' ')
  
       LongestName = 0
+
       [[LongestName]] = 0
       for N.F = 1 to NumFiles
+
       for N.F = 1 to [[NumFiles]]
         OneProgram = field( FileList, ' ', N.F )
+
         [[OneProgram]] = field( [[FileList]], ' ', N.F )
         if len(OneProgram) > LongestName then LongestName = len(OneProgram)
+
         if len([[OneProgram]]) > [[LongestName]] then [[LongestName]] = len([[OneProgram]])
 
       next N.F
 
       next N.F
       NameFmt = 'L#':LongestName
+
       [[NameFmt]] = 'L#':[[LongestName]]
  
       for N.F = 1 to NumFiles
+
       for N.F = 1 to [[NumFiles]]
         OneProgram = field( FileList, ' ', N.F )
+
         [[OneProgram]] = field( [[FileList]], ' ', N.F )
         ProgramFile = field( OneProgram, '/', 1)
+
         [[ProgramFile]] = field( [[OneProgram]], '/', 1)
         ProgramID  = field( OneProgram, '/', 2)
+
         [[ProgramID]]   = field( [[OneProgram]], '/', 2)
         if not( OPEN.FILE( ProgramFile, '', PROGRAM.FILE,  Err ) ) then stopm Err
+
         if not( OPEN.FILE( [[ProgramFile]], '', PROGRAM.FILE,  Err ) ) then stopm Err
         read ProgramCode from PROGRAM.FILE, ProgramID else crt "No item named:  ":ProgramID ; return
+
         read [[ProgramCode]] from PROGRAM.FILE, [[ProgramID]] else crt "No item named:  ":[[ProgramID]] ; return
         crt OneProgram NameFmt:' ':ProgramCode<4>
+
         crt [[OneProgram]] [[NameFmt]]:' ':[[ProgramCode]]<4>
 
       next N.F
 
       next N.F
 
       crt
 
       crt
Line 169: Line 169:
 
     case svnOp = "COMPILE" or svnOp = "BASIC" or svnOp = "CATALOG"
 
     case svnOp = "COMPILE" or svnOp = "BASIC" or svnOp = "CATALOG"
  
       FileList = trim( FileList )
+
       [[FileList]] = trim( [[FileList]] )
       NumFiles = dcount(FileList, ' ')
+
       [[NumFiles]] = dcount([[FileList]], ' ')
       for N.F = 1 to NumFiles
+
       for N.F = 1 to [[NumFiles]]
         OneProgram = field( FileList, ' ', N.F )
+
         [[OneProgram]] = field( [[FileList]], ' ', N.F )
         convert '/' to ' ' in OneProgram
+
         convert '/' to ' ' in [[OneProgram]]
         if svnOp = "COMPILE" or svnOp = "BASIC" then TclCommand = "BASIC" else TclCommand = "CATALOG"
+
         if svnOp = "COMPILE" or svnOp = "BASIC" then [[TclCommand]] = "BASIC" else [[TclCommand]] = "CATALOG"
         execute TclCommand:" ":OneProgram
+
         execute [[TclCommand]]:" ":[[OneProgram]]
 
       next N.F
 
       next N.F
  
 
     case svnOp = "LISTS"  ;*  Special hack: just to use the code that reads the Release
 
     case svnOp = "LISTS"  ;*  Special hack: just to use the code that reads the Release
  
       gosub SaveProgramLists
+
       gosub [[SaveProgramLists]]
  
 
     case 1
 
     case 1
Line 187: Line 187:
 
       call APPEND.UNIX.LOG (svnScript, logFile, aulErr)
 
       call APPEND.UNIX.LOG (svnScript, logFile, aulErr)
  
       if DisplayCmd then
+
       if [[DisplayCmd]] then
 
         crt svnScript ; crt
 
         crt svnScript ; crt
 
         input j ; j = upcase(j)
 
         input j ; j = upcase(j)
Line 193: Line 193:
 
       end
 
       end
  
       if not(NoExecute) then
+
       if not([[NoExecute]]) then
         execute "SH -c \":svnScript:"\" capturing SvnResponse
+
         execute "SH -c \":svnScript:"\" capturing [[SvnResponse]]
 
       end
 
       end
       OutputResponse = SvnResponse
+
       [[OutputResponse]] = [[SvnResponse]]
       convert @FM to char(10) in OutputResponse
+
       convert @FM to char(10) in [[OutputResponse]]
       crt OutputResponse
+
       crt [[OutputResponse]]
  
 
   end case
 
   end case
Line 204: Line 204:
 
return
 
return
  
ExecutePostSvnCommands:
+
[[ExecutePostSvnCommands]]:
 
   *  Now do anything special we need 'post SVN' :
 
   *  Now do anything special we need 'post SVN' :
 
   begin case
 
   begin case
  
 
     case svnOp = "DIFF"
 
     case svnOp = "DIFF"
       if SvnResponse = '' then crt "The current version does not differ from what's checked in." ; crt
+
       if [[SvnResponse]] = '' then crt "The current version does not differ from what's checked in." ; crt
  
 
     case svnOp = "COMMIT"
 
     case svnOp = "COMMIT"
       if ReleaseNumber # '' then  ;*  Separate 'if' because SvnLine will only be defined for -R :
+
       if [[ReleaseNumber]] # '' then  ;*  Separate 'if' because [[SvnLine]] will only be defined for -R :
         if SvnLine # 0 then      ;*  Release needs the SVN number:
+
         if [[SvnLine]] # 0 then      ;*  Release needs the SVN number:
           gosub AddReleaseNumber
+
           gosub [[AddReleaseNumber]]
 
         end
 
         end
 
       end
 
       end
  
 
     case svnOp = "STATUS"
 
     case svnOp = "STATUS"
       if ReleaseNumber # '' then  ;*  SvnLine will only be defined for -R :
+
       if [[ReleaseNumber]] # '' then  ;*  [[SvnLine]] will only be defined for -R :
         gosub CheckReleaseStatus
+
         gosub [[CheckReleaseStatus]]
 
       end
 
       end
  
Line 226: Line 226:
 
return
 
return
  
SaveProgramLists:
+
[[SaveProgramLists]]:
 
   if not(OPEN.FILE("&SAVEDLISTS&", "", SAVEDLISTS.FILE, Err)) then stopm Err
 
   if not(OPEN.FILE("&SAVEDLISTS&", "", SAVEDLISTS.FILE, Err)) then stopm Err
   FileList = trim( FileList )
+
   [[FileList]] = trim( [[FileList]] )
   NumFiles = dcount(FileList, ' ')
+
   [[NumFiles]] = dcount([[FileList]], ' ')
   F.P = 0 ; CurrentFile = '~' ; ItemList = ''
+
   F.P = 0 ; [[CurrentFile]] = '~' ; [[ItemList]] = ''
 
   loop
 
   loop
 
     F.P += 1
 
     F.P += 1
   while F.P <= NumFiles do
+
   while F.P <= [[NumFiles]] do
     OneProgram = field( FileList, ' ', F.P )
+
     [[OneProgram]] = field( [[FileList]], ' ', F.P )
     ProgramFile = field( OneProgram, '/', 1 )
+
     [[ProgramFile]] = field( [[OneProgram]], '/', 1 )
     ProgramItem = field( OneProgram, '/', 2 )
+
     [[ProgramItem]] = field( [[OneProgram]], '/', 2 )
     if ProgramFile # CurrentFile then
+
     if [[ProgramFile]] # [[CurrentFile]] then
       gosub SaveLastList
+
       gosub [[SaveLastList]]
       CurrentFile = ProgramFile
+
       [[CurrentFile]] = [[ProgramFile]]
 
     end
 
     end
     ItemList<-1> = ProgramItem
+
     [[ItemList]]<-1> = [[ProgramItem]]
 
   repeat
 
   repeat
   gosub SaveLastList
+
   gosub [[SaveLastList]]
 
return
 
return
  
SaveLastList:
+
[[SaveLastList]]:
   if CurrentFile # '~' then
+
   if [[CurrentFile]] # '~' then
     ListName = CurrentFile:"_":ReleaseNumber
+
     [[ListName]] = [[CurrentFile]]:"_":[[ReleaseNumber]]
     crt "Writing list ":ListName
+
     crt "Writing list ":[[ListName]]
     write ItemList on SAVEDLISTS.FILE, ListName
+
     write [[ItemList]] on SAVEDLISTS.FILE, [[ListName]]
     ItemList = ''
+
     [[ItemList]] = ''
 
   end
 
   end
 
return
 
return
Line 257: Line 257:
 
* =======================================================================================
 
* =======================================================================================
  
AddReleaseNumber:
+
[[AddReleaseNumber]]:
   RevisionNumber = ''
+
   [[RevisionNumber]] = ''
   NumResponseLines = dcount( SvnResponse, @FM )
+
   [[NumResponseLines]] = dcount( [[SvnResponse]], @FM )
   for N.R.L = NumResponseLines to 1 step -1  ;*  Go backward since it's at the end:
+
   for N.R.L = [[NumResponseLines]] to 1 step -1  ;*  Go backward since it's at the end:
     ResponseLn = SvnResponse<N.R.L>
+
     [[ResponseLn]] = [[SvnResponse]]<N.R.L>
     if ResponseLn[1,18] = "Committed revision" then
+
     if [[ResponseLn]][1,18] = "Committed revision" then
       RevisionNumber = trim( field(ResponseLn[19,999], '.', 1) )
+
       [[RevisionNumber]] = trim( field([[ResponseLn]][19,999], '.', 1) )
 
     end
 
     end
 
   next N.R.L
 
   next N.R.L
   if RevisionNumber # '' then
+
   if [[RevisionNumber]] # '' then
     ReleaseText<SvnLine> = "SVN: ":RevisionNumber
+
     [[ReleaseText]]<SvnLine> = "SVN: ":[[RevisionNumber]]
     convert @FM to char(10) in ReleaseText
+
     convert @FM to char(10) in [[ReleaseText]]
     *  Was "/home/release/":ReleaseNumber:"/flist" but maybe in 'released' now?:
+
     *  Was "/home/release/":[[ReleaseNumber]]:"/flist" but maybe in 'released' now?:
     call WRITE.UNIX( ReleaseText, flistPath, Err)
+
     call WRITE.UNIX( [[ReleaseText]], flistPath, Err)
 
   end
 
   end
 
return
 
return
Line 276: Line 276:
 
*  SVN STATUS -R xxxx : Check if the SVN # of each item is > the Release's #
 
*  SVN STATUS -R xxxx : Check if the SVN # of each item is > the Release's #
  
CheckReleaseStatus:
+
[[CheckReleaseStatus]]:
   RevisionNumber = field( ReleaseText<SvnLine>, ' ', 2)
+
   [[RevisionNumber]] = field( [[ReleaseText]]<SvnLine>, ' ', 2)
   if RevisionNumber = '' then return
+
   if [[RevisionNumber]] = '' then return
  
   if ReleaseLocation # '' then crt ; crt ReleaseLocation ; crt
+
   if [[ReleaseLocation]] # '' then crt ; crt [[ReleaseLocation]] ; crt
  
   crt ; crt "Checking that each file is before Revision ":RevisionNumber:'...' ; crt
+
   crt ; crt "Checking that each file is before Revision ":[[RevisionNumber]]:'...' ; crt
   NumResponseLines = dcount( SvnResponse, @FM )
+
   [[NumResponseLines]] = dcount( [[SvnResponse]], @FM )
   for N.R.L = 1 to NumResponseLines
+
   for N.R.L = 1 to [[NumResponseLines]]
     ResponseLn = SvnResponse<N.R.L>
+
     [[ResponseLn]] = [[SvnResponse]]<N.R.L>
     Revs = trim( ResponseLn[12, 9999] )  ;*  Kind of a hack ? How else though ?
+
     Revs = trim( [[ResponseLn]][12, 9999] )  ;*  Kind of a hack ? How else though ?
     LastCommitted = field(Revs, ' ', 2)
+
     [[LastCommitted]] = field(Revs, ' ', 2)
     if LastCommitted > RevisionNumber then
+
     if [[LastCommitted]] > [[RevisionNumber]] then
 
       Path = field( Revs, ' ', 4)
 
       Path = field( Revs, ' ', 4)
       crt Path:" has a Revision Number (":LastCommitted:") AFTER this Releases Revision # ":RevisionNumber:" ! (one-off Commit ?)"
+
       crt Path:" has a Revision Number (":[[LastCommitted]]:") AFTER this Releases Revision # ":[[RevisionNumber]]:" ! (one-off Commit ?)"
 
     end
 
     end
 
   next N.R.L
 
   next N.R.L
Line 296: Line 296:
 
return
 
return
  
DisplayErrors:
+
[[DisplayErrors]]:
 
   if Err # '' then
 
   if Err # '' then
 
     crt
 
     crt
 
     crt 'ERROR ! : ':Err<1>
 
     crt 'ERROR ! : ':Err<1>
     NumErrs = dcount(Err, @FM)
+
     [[NumErrs]] = dcount(Err, @FM)
     for N.E = 2 to NumErrs
+
     for N.E = 2 to [[NumErrs]]
 
       crt '          ':Err<N.E>
 
       crt '          ':Err<N.E>
 
     next N.E
 
     next N.E
Line 310: Line 310:
 
return
 
return
  
ReadRelease:
+
[[ReadRelease]]:
   ReleaseLocation = ''
+
   [[ReleaseLocation]] = ''
   flistPath = "/home/release/":ReleaseNumber:"/flist"
+
   flistPath = "/home/release/":[[ReleaseNumber]]:"/flist"
   call READ.UNIX( ReleaseText, flistPath, Err)
+
   call READ.UNIX( [[ReleaseText]], flistPath, Err)
 
   if Err # '' then
 
   if Err # '' then
     ReleaseLocation = ' ** RELEASED **'
+
     [[ReleaseLocation]] = ' ** RELEASED **'
     flistPath = "/home/release/released/":ReleaseNumber:"/flist"
+
     flistPath = "/home/release/released/":[[ReleaseNumber]]:"/flist"
     call READ.UNIX( ReleaseText, flistPath, Err2)
+
     call READ.UNIX( [[ReleaseText]], flistPath, Err2)
 
     if Err2 # '' then
 
     if Err2 # '' then
 
       crt Err ; crt Err2 ; input j ; return
 
       crt Err ; crt Err2 ; input j ; return
Line 324: Line 324:
 
   end
 
   end
  
   convert char(10):char(13) to @FM in ReleaseText
+
   convert char(10):char(13) to @FM in [[ReleaseText]]
   SvnLine = 0 ;* Track the 'SVN:' line to append the # if we are Committing and there's not one already
+
   [[SvnLine]] = 0 ;* Track the 'SVN:' line to append the # if we are Committing and there's not one already
   NumLines = dcount( ReleaseText, @FM )
+
   [[NumLines]] = dcount( [[ReleaseText]], @FM )
   for N.L = 1 to NumLines
+
   for N.L = 1 to [[NumLines]]
     LN = trim( ReleaseText<N.L> )
+
     LN = trim( [[ReleaseText]]<N.L> )
 
     begin case
 
     begin case
       case LN[1,2] = '**' and CommitComment = ''
+
       case LN[1,2] = '**' and [[CommitComment]] = ''
         CommitComment = LN[3, 99999]      ;*  Special single comment line used for Commit
+
         [[CommitComment]] = LN[3, 99999]      ;*  Special single comment line used for Commit
 
       case LN[1,1] = '*' or LN[1,1] = '#'  ;*  Ignore comments
 
       case LN[1,1] = '*' or LN[1,1] = '#'  ;*  Ignore comments
 
       case index(LN, ':', 1) # 0          ;*  Handle special tags :
 
       case index(LN, ':', 1) # 0          ;*  Handle special tags :
 
         if LN[1,4] = "SVN:" then          ;*  Is this the "SVN:" line ?
 
         if LN[1,4] = "SVN:" then          ;*  Is this the "SVN:" line ?
           SvnLine = N.L                    ;*  Remember where
+
           [[SvnLine]] = N.L                    ;*  Remember where
 
         end
 
         end
 
       case LN # ''                        ;*  Finally handle normal lines:
 
       case LN # ''                        ;*  Finally handle normal lines:
         Item = LN ; gosub AddItem
+
         Item = LN ; gosub [[AddItem]]
 
     end case
 
     end case
 
   next N.L
 
   next N.L
 
return
 
return
  
AddItem:
+
[[AddItem]]:
   FileName = field(Item, '/', 1) ; ItemID = field(Item, '/', 2)
+
   [[FileName]] = field(Item, '/', 1) ; [[ItemID]] = field(Item, '/', 2)
   open FileName to File then
+
   open [[FileName]] to File then
     FileList := Item:' '  ;*  Keep list because some things don't need to be in UV ?:
+
     [[FileList]] := Item:' '  ;*  Keep list because some things don't need to be in UV ?:
     read dummy from File, ItemID else
+
     read dummy from File, [[ItemID]] else
       FileErrs<-1> = ItemID:" is not in ":FileName
+
       [[FileErrs]]<-1> = [[ItemID]]:" is not in ":[[FileName]]
 
     end
 
     end
 
   end else
 
   end else
     if FileName = 'DICT' then  ;*  Special case: make it act like a BP ?
+
     if [[FileName]] = 'DICT' then  ;*  Special case: make it act like a BP ?
       FileList := Item:' '    ;*  Just like above ?
+
       [[FileList]] := Item:' '    ;*  Just like above ?
 
     end else
 
     end else
       FileErrs<-1> = FileName:" is not a valid BP file/directory."
+
       [[FileErrs]]<-1> = [[FileName]]:" is not a valid BP file/directory."
 
     end
 
     end
 
   end
 
   end
 
return
 
return
  
GetCommitComment:
+
[[GetCommitComment]]:
   * Add spaces, to allow for the "new" comment to be longer than 'CommitComment'. A MR.IN characteristic.
+
   * Add spaces, to allow for the "new" comment to be longer than '[[CommitComment]]'. A MR.IN characteristic.
   commitLength = len(CommitComment)
+
   commitLength = len([[CommitComment]])
   DisplayComment = CommitComment:spaces(100-commitLength)
+
   [[DisplayComment]] = [[CommitComment]]:spaces(100-commitLength)
   crt "Enter comment:": ; call MR.IN( DisplayComment, '', OUT )
+
   crt "Enter comment:": ; call MR.IN( [[DisplayComment]], '', OUT )
 
   if OUT = "ESC" or OUT = 'HOME' then stop
 
   if OUT = "ESC" or OUT = 'HOME' then stop
   CommitComment = trim(DisplayComment)
+
   [[CommitComment]] = trim([[DisplayComment]])
 
return
 
return
  
 
* =======================================================================================
 
* =======================================================================================
  
*  Set all Option flags and set FileList and FileErrs. Note we don't handle the errors
+
*  Set all Option flags and set [[FileList]] and [[FileErrs]]. Note we don't handle the errors
 
*  now because some options don't require them anyway.
 
*  now because some options don't require them anyway.
  
ParseCommandLine:
+
[[ParseCommandLine]]:
   CmdLineOptions = "SINGLEPARAM"  ;*  for -M option
+
   [[CmdLineOptions]] = "SINGLEPARAM"  ;*  for -M option
   call PARSE.CMDLINE( @SENTENCE, mat CMDLINE, CmdLineOptions )
+
   call PARSE.CMDLINE( @SENTENCE, mat CMDLINE, [[CmdLineOptions]] )
 
   if CMD.HELP then gosub Help ; stop
 
   if CMD.HELP then gosub Help ; stop
 
   svnOp = CMD.ARG.S<1, 1>
 
   svnOp = CMD.ARG.S<1, 1>
   FileName = CMD.ARG.S<1, 2>
+
   [[FileName]] = CMD.ARG.S<1, 2>
   locate 'D' in CMD.FLAG.S<1> setting dum then DisplayCmd = @TRUE else DisplayCmd = @FALSE
+
   locate 'D' in CMD.FLAG.S<1> setting dum then [[DisplayCmd]] = @TRUE else [[DisplayCmd]] = @FALSE
   locate 'L' in CMD.FLAG.S<1> setting SelectListLoc then
+
   locate 'L' in CMD.FLAG.S<1> setting [[SelectListLoc]] then
     SelectListName = CMD.PARAM.S<1, SelectListLoc, 1>
+
     [[SelectListName]] = CMD.PARAM.S<1, [[SelectListLoc]], 1>
   end else SelectListName = ''
+
   end else [[SelectListName]] = ''
   locate 'N' in CMD.FLAG.S<1> setting dum then NoExecute = @TRUE else NoExecute = @FALSE
+
   locate 'N' in CMD.FLAG.S<1> setting dum then [[NoExecute]] = @TRUE else [[NoExecute]] = @FALSE
   locate 'M' in CMD.FLAG.S<1> setting MessagePos then
+
   locate 'M' in CMD.FLAG.S<1> setting [[MessagePos]] then
     CommitComment = CMD.PARAM.S<1, MessagePos, 1>  ;*  'SINGLEPARAM' is set so there's only one line
+
     [[CommitComment]] = CMD.PARAM.S<1, [[MessagePos]], 1>  ;*  'SINGLEPARAM' is set so there's only one line
   end else CommitComment = ''
+
   end else [[CommitComment]] = ''
   locate 'R' in CMD.FLAG.S<1> setting ReleasePos then
+
   locate 'R' in CMD.FLAG.S<1> setting [[ReleasePos]] then
     ReleaseNumber = CMD.PARAM.S<1, ReleasePos, 1>
+
     [[ReleaseNumber]] = CMD.PARAM.S<1, [[ReleasePos]], 1>
   end else ReleaseNumber = ''
+
   end else [[ReleaseNumber]] = ''
 
   locate 'V' in CMD.FLAG.S<1> setting dum then Verbose = @TRUE else Verbose = @FALSE
 
   locate 'V' in CMD.FLAG.S<1> setting dum then Verbose = @TRUE else Verbose = @FALSE
   locate 'P' in CMD.FLAG.S<1> setting PropertyNameAndValueLoc then
+
   locate 'P' in CMD.FLAG.S<1> setting [[PropertyNameAndValueLoc]] then
     PropertyNameAndValue = CMD.PARAM.S<1, PropertyNameAndValueLoc, 1>
+
     [[PropertyNameAndValue]] = CMD.PARAM.S<1, [[PropertyNameAndValueLoc]], 1>
   end else PropertyNameAndValue = ''
+
   end else [[PropertyNameAndValue]] = ''
   FileList  = ""  ;*  Space separated; each item is a path from /u/dsisrc :
+
   [[FileList]] = ""  ;*  Space separated; each item is a path from /u/dsisrc :
   FileErrs  = ""
+
   [[FileErrs]] = ""
  
   begin case      ;*  Lots of ways to get the FileList:
+
   begin case      ;*  Lots of ways to get the [[FileList]]:
     case ReleaseNumber  # '' ; gosub ReadRelease
+
     case [[ReleaseNumber]] # '' ; gosub [[ReadRelease]]
     case SelectListName # '' ;* Use the SELECT list if provided
+
     case [[SelectListName]] # '' ;* Use the SELECT list if provided
       getlist SelectListName else Err = "Unable to read Select List ": SelectListName ; return
+
       getlist [[SelectListName]] else Err = "Unable to read Select List ": [[SelectListName]] ; return
       loop while readnext ItemID do
+
       loop while readnext [[ItemID]] do
         Item = FileName:'/':ItemID ; gosub AddItem
+
         Item = [[FileName]]:'/':[[ItemID]] ; gosub [[AddItem]]
 
       repeat
 
       repeat
 
     case 1  ;* Get the individual files if no "-L" option was specified
 
     case 1  ;* Get the individual files if no "-L" option was specified
 
       for N.A = 3 to CMD.NUM.ARGS  ;* We get the files as arguments 3 and more
 
       for N.A = 3 to CMD.NUM.ARGS  ;* We get the files as arguments 3 and more
         Item = FileName:'/':CMD.ARG.S<1,N.A> ; gosub AddItem
+
         Item = [[FileName]]:'/':CMD.ARG.S<1,N.A> ; gosub [[AddItem]]
 
       next N.A
 
       next N.A
 
   end case
 
   end case
Line 414: Line 414:
  
 
Help:
 
Help:
   crt 'SVN <command> { <BP_Dir> <item> ... | -L <save-list> | -R <release#> } [-N][-M "message"][-V][-D][-P <PropName=PropVal>]'
+
   crt 'SVN <command> { <BP_Dir> <item> ... | -L <save-list> | -R <release#> } [-N][-M "message"][-V][-D][-P <[[PropName]]=PropVal>]'
 
   crt
 
   crt
 
   crt " where <command> is COMPILE, COMMIT, ADD, DELETE, DIFF, INFO, LOG, REVERT, STATUS, HELP, PROPSET. Options:"
 
   crt " where <command> is COMPILE, COMMIT, ADD, DELETE, DIFF, INFO, LOG, REVERT, STATUS, HELP, PROPSET. Options:"
Line 433: Line 433:
 
   crt "  SVN DIFF DSI.BP AR.FREEZE            : Show the difference between the local copy and what's in SVN"
 
   crt "  SVN DIFF DSI.BP AR.FREEZE            : Show the difference between the local copy and what's in SVN"
 
   crt "  SVN INFO DSI.BP AR.FREEZE PMTS      : Show misc info about what's in SVN"
 
   crt "  SVN INFO DSI.BP AR.FREEZE PMTS      : Show misc info about what's in SVN"
   crt "  SVN CLEANUP /u/dsisrc/DSI.BP        : Execute cleanup on DSI.BP directory (if something is locked, etc)"
+
   crt "  SVN CLEANUP /u/dsisrc[[/DSI]].BP        : Execute cleanup on DSI.BP directory (if something is locked, etc)"
 
   crt "  SVN LOG DSI.BP AR.FREEZE            : List of historical changes"
 
   crt "  SVN LOG DSI.BP AR.FREEZE            : List of historical changes"
 
   crt
 
   crt

Latest revision as of 23:48, 26 February 2015

HomePage>>SourceCode>>BasicSource>>SvnWrapper>>SVN

SVN Source code; once all source is compiled and cataloged, 'SVN -H' will show usage.

* ===================================== SVN =============================================
* @TCL: SVN wrapper, to be run on the UV prompt
* =======================================================================================
* 04.Oct.2013 james: Check /released/ folder too when doing STATUS
* 20.Dec.2012 james: Add CATALOG
* 07.Sep.2012 james: New 'COMMENTS' option to see the latest comment for each program.
* 12.May.2011 james: Handle 'DICT/' in release (flist) files.
* 10.Aug.2010 james: Add 'COMPILE' option to check a release before it goes out.
* 07.Oct.2009 james: Add 'UPDATE'; only add -m if '[[RequiresComment]]'.. IS THIS OK !?
* 30.Jun.2009 james: Add '[[CheckReleaseStatus]]' to make sure nothing was committed after
*                    the Release's Revision Number.
* 17.Nov.2008 chrisg: Added support for CLEANUP command
* 12.Jul.2008 chrisg: Added support for SVN PROPSET command
* 22.Apr.2008 manoj: Fixed a bug that limit the length of a new comment to the comment on 
*                    line 4
* 11.Apr.2008 jim: Use the line 4 comment for the [[CommitComment]] ONLY IF there's one item.
* 11.Feb.2008 jim: [[RequiresFileList]] = @FALSE for DELETE and STATUS; so those still work
*                  if files are in SVN but not in UV.
* 14.Jan.2008 manoj: Added DELETE
* 10.Jan.2008 manoj: Added revert
* 02.Jan.2008 jim: Restructure to improve error handling, etc.
* 31.Aug.2007 manoj: Created
* =======================================================================================
* $Id: SVN 44131 2013-11-12 02:57:36Z jim $
* =======================================================================================
*
* This invokes the svn command, with the proper svn URL and REAL.USER name
*
* Ex:
*
*  svn commit svn+ssh://manoj@svn.docmagic.com/opt/svn/dsi[[/Database/Universe/trunk/dsisrc]]
*
* Trac Reference: http://trac/dsi/wiki/UniverseInSvn
*
* =======================================================================================

  $include RMS.BP EQU.CMDLINE

  equate SVN$CMD          to "/usr/bin/svn"

  deffun GET.REALUSER( Err )
  deffun OPEN.FILE( FILENAME, FLAGS, FILEVAR, ERR.MSG )

  username = GET.REALUSER( Err ) ; if Err # '' then stopm Err  ;*  Err not yet implemented anyway
  logFile  = "log[[/SVN]].LOG"

  gosub [[ParseCommandLine]]
  gosub [[PrepareSvnCommand]]

  if Err # '' then
    gosub [[DisplayErrors]]
  end else

    gosub [[ExecuteSvnCommand]]
    gosub [[ExecutePostSvnCommands]]

  end
return

* =======================================================================================

[[PrepareSvnCommand]]:
  [[RequiresFileList]] = @FALSE
  [[RequiresComment]]  = @FALSE
  * Also add svnOp below (in the [[ShowHelp]] )
  begin case
    case svnOp = "COMMENTS" ; [[RequiresFileList]] = @TRUE  ;*  NOT REALLY AN SVN COMMAND BUT IT'S HANDY !
    case svnOp = "BASIC"    ; [[RequiresFileList]] = @TRUE  ;*  NOT REALLY AN SVN COMMAND BUT IT'S HANDY !
    case svnOp = "COMPILE"  ; [[RequiresFileList]] = @TRUE  ;*  NOT REALLY AN SVN COMMAND BUT IT'S HANDY !
    case svnOp = "CATALOG"  ; [[RequiresFileList]] = @TRUE  ;*  NOT REALLY AN SVN COMMAND BUT IT'S HANDY !
    case svnOp = "COMMIT"   ; [[RequiresFileList]] = @TRUE  ; [[RequiresComment]] = @TRUE
    case svnOp = "ADD"      ; [[RequiresFileList]] = @TRUE
    case svnOp = "UPDATE"   ; [[RequiresFileList]] = @TRUE  ;*  Is this dangerous !? Just for messed up SVN !?!
    case svnOp = "DELETE"   ; [[RequiresFileList]] = @FALSE ;*  Allow delete from SVN with no UV item ?
    case svnOp = "DIFF"     ; [[RequiresFileList]] = @TRUE
    case svnOp = "INFO"     ; [[RequiresFileList]] = @TRUE
    case svnOp = "LISTS"    ; [[RequiresFileList]] = @TRUE  ;*  NOT REALLY AN SVN COMMAND BUT IT'S HANDY !
    case svnOp = "LOG"      ; [[RequiresFileList]] = @TRUE
    case svnOp = "REVERT"   ; [[RequiresFileList]] = @TRUE
    case svnOp = "PROPSET"  ; [[RequiresFileList]] = @TRUE
    
      if [[PropertyNameAndValue]] = '' then 
        Err = svnOp:" requires -P, see help"; return
      end else
        [[PropertyNameAndValue]] = EREPLACE([[PropertyNameAndValue]], "=", " ")
      end

    case svnOp = "STATUS"  ; * [[FileList]] is NOT required; but use it if it's there.

      if [[FileList]] = '' then
        if [[FileName]] # '' then
          [[FileList]] = [[FileName]]
        end else
          [[FileList]] = "DSI.BP DA.BP WEB.BP RMS.BP"
        end
      end else Verbose = @TRUE ;*  Force Verbose if you list specific items.
      if Verbose then [[FileList]] := " -v"  ;*  Always VERBOSE (show lines NOT changed too...)
      [[CommitComment]] = ''   ;*  May have been set from '[[ReadRelease]]' ?
      
    case svnOp = "CLEANUP" ; [[FileList]] = [[FileName]]
    case svnOp = "HELP"    ; [[FileList]] = downcase([[FileName]]) ;*  NO options required; but may have 2nd parameter
    case 1
      Err = "Invalid SVN Operation '":svnOp
  end case

  if [[FileErrs]] # '' then crt [[FileErrs]] ; input j

  if [[RequiresFileList]] then
    Err = [[FileErrs]] ; if Err # '' then return
    if [[FileList]] = '' then Err = svnOp:" requires a File and Item name" ; return
  end

  if [[RequiresComment]] and [[CommitComment]] = '' then
    if CMD.NUM.ARGS = 3 then  ;*  Only 1 file to commit: use it's comment (Tacky ?) :
      [[FileName]] = CMD.ARG.S<1, 2>
      [[ItemID]]   = CMD.ARG.S<1, 3>
      open [[FileName]] to File then
        read [[ProgramItem]] from File, [[ItemID]] then
          [[CommentLine]] = [[ProgramItem]]<4>
          [[CommentUser]] = field( [[CommentLine]], ' ', 3 )
          [[CommitComment]] = [[CommentLine]][ col2() + 1, 999 ]
        end else [[CommitComment]] = ""  ;*  Why would this be ? Throw an error ?
      end
    end
    gosub [[GetCommitComment]]
    if [[CommitComment]] = "" then Err = "Cannot ":svnOp:" with an empty comment"
  end
return

[[ExecuteSvnCommand]]:
  *  Force the username by passing to the "sudo" command below
  svnCommand = SVN$CMD:' ':downcase(svnOp):' ':[[PropertyNameAndValue]]:' ':[[FileList]]
  if [[RequiresComment]] and [[CommitComment]] # '' then
    svnCommand := ' -m "':[[CommitComment]]:'"'
  end

  begin case
    case svnOp = "COMMENTS"  ;*  Special hack: just to use the code that reads the Release

      crt
      crt " (comments are always from the CURRENT version...)"
      crt
      [[FileList]] = trim( [[FileList]] )
      [[NumFiles]] = dcount([[FileList]], ' ')

      [[LongestName]] = 0
      for N.F = 1 to [[NumFiles]]
        [[OneProgram]] = field( [[FileList]], ' ', N.F )
        if len([[OneProgram]]) > [[LongestName]] then [[LongestName]] = len([[OneProgram]])
      next N.F
      [[NameFmt]] = 'L#':[[LongestName]]

      for N.F = 1 to [[NumFiles]]
        [[OneProgram]] = field( [[FileList]], ' ', N.F )
        [[ProgramFile]] = field( [[OneProgram]], '/', 1)
        [[ProgramID]]   = field( [[OneProgram]], '/', 2)
        if not( OPEN.FILE( [[ProgramFile]], '', PROGRAM.FILE,  Err ) ) then stopm Err
        read [[ProgramCode]] from PROGRAM.FILE, [[ProgramID]] else crt "No item named:  ":[[ProgramID]] ; return
        crt [[OneProgram]] [[NameFmt]]:' ':[[ProgramCode]]<4>
      next N.F
      crt

    *  Special hack: just to use the code that reads the Release
    case svnOp = "COMPILE" or svnOp = "BASIC" or svnOp = "CATALOG"

      [[FileList]] = trim( [[FileList]] )
      [[NumFiles]] = dcount([[FileList]], ' ')
      for N.F = 1 to [[NumFiles]]
        [[OneProgram]] = field( [[FileList]], ' ', N.F )
        convert '/' to ' ' in [[OneProgram]]
        if svnOp = "COMPILE" or svnOp = "BASIC" then [[TclCommand]] = "BASIC" else [[TclCommand]] = "CATALOG"
        execute [[TclCommand]]:" ":[[OneProgram]]
      next N.F

    case svnOp = "LISTS"  ;*  Special hack: just to use the code that reads the Release

      gosub [[SaveProgramLists]]

    case 1

      svnScript  = "(cd /u/dsisrc; sudo -u ":username:" ":svnCommand:" )"
      call APPEND.UNIX.LOG (svnScript, logFile, aulErr)

      if [[DisplayCmd]] then
        crt svnScript ; crt
        input j ; j = upcase(j)
        if j = 'X' or j = 'Q' then stop
      end

      if not([[NoExecute]]) then
        execute "SH -c \":svnScript:"\" capturing [[SvnResponse]]
      end
      [[OutputResponse]] = [[SvnResponse]]
      convert @FM to char(10) in [[OutputResponse]]
      crt [[OutputResponse]]

  end case

return

[[ExecutePostSvnCommands]]:
  *  Now do anything special we need 'post SVN' :
  begin case

    case svnOp = "DIFF"
      if [[SvnResponse]] = '' then crt "The current version does not differ from what's checked in." ; crt

    case svnOp = "COMMIT"
      if [[ReleaseNumber]] # '' then  ;*  Separate 'if' because [[SvnLine]] will only be defined for -R :
        if [[SvnLine]] # 0 then       ;*  Release needs the SVN number:
          gosub [[AddReleaseNumber]]
        end
      end

    case svnOp = "STATUS"
      if [[ReleaseNumber]] # '' then  ;*  [[SvnLine]] will only be defined for -R :
        gosub [[CheckReleaseStatus]]
      end

  end case
return

[[SaveProgramLists]]:
  if not(OPEN.FILE("&SAVEDLISTS&", "", SAVEDLISTS.FILE, Err)) then stopm Err
  [[FileList]] = trim( [[FileList]] )
  [[NumFiles]] = dcount([[FileList]], ' ')
  F.P = 0 ; [[CurrentFile]] = '~' ; [[ItemList]] = ''
  loop
    F.P += 1
   while F.P <= [[NumFiles]] do
    [[OneProgram]] = field( [[FileList]], ' ', F.P )
    [[ProgramFile]] = field( [[OneProgram]], '/', 1 )
    [[ProgramItem]] = field( [[OneProgram]], '/', 2 )
    if [[ProgramFile]] # [[CurrentFile]] then
      gosub [[SaveLastList]]
      [[CurrentFile]] = [[ProgramFile]]
    end
    [[ItemList]]<-1> = [[ProgramItem]]
  repeat
  gosub [[SaveLastList]]
return

[[SaveLastList]]:
  if [[CurrentFile]] # '~' then
    [[ListName]] = [[CurrentFile]]:"_":[[ReleaseNumber]]
    crt "Writing list ":[[ListName]]
    write [[ItemList]] on SAVEDLISTS.FILE, [[ListName]]
    [[ItemList]] = ''
  end
return

* =======================================================================================

[[AddReleaseNumber]]:
  [[RevisionNumber]] = ''
  [[NumResponseLines]] = dcount( [[SvnResponse]], @FM )
  for N.R.L = [[NumResponseLines]] to 1 step -1  ;*  Go backward since it's at the end:
    [[ResponseLn]] = [[SvnResponse]]<N.R.L>
    if [[ResponseLn]][1,18] = "Committed revision" then
      [[RevisionNumber]] = trim( field([[ResponseLn]][19,999], '.', 1) )
    end
  next N.R.L
  if [[RevisionNumber]] # '' then
    [[ReleaseText]]<SvnLine> = "SVN: ":[[RevisionNumber]]
    convert @FM to char(10) in [[ReleaseText]]
    *  Was "/home/release/":[[ReleaseNumber]]:"/flist" but maybe in 'released' now?:
    call WRITE.UNIX( [[ReleaseText]], flistPath, Err)
  end
return

*  SVN STATUS -R xxxx : Check if the SVN # of each item is > the Release's #

[[CheckReleaseStatus]]:
  [[RevisionNumber]] = field( [[ReleaseText]]<SvnLine>, ' ', 2)
  if [[RevisionNumber]] = '' then return

  if [[ReleaseLocation]] # '' then crt ; crt [[ReleaseLocation]] ; crt

  crt ; crt "Checking that each file is before Revision ":[[RevisionNumber]]:'...' ; crt
  [[NumResponseLines]] = dcount( [[SvnResponse]], @FM )
  for N.R.L = 1 to [[NumResponseLines]]
    [[ResponseLn]] = [[SvnResponse]]<N.R.L>
    Revs = trim( [[ResponseLn]][12, 9999] )  ;*  Kind of a hack ? How else though ?
    [[LastCommitted]] = field(Revs, ' ', 2)
    if [[LastCommitted]] > [[RevisionNumber]] then
      Path = field( Revs, ' ', 4)
      crt Path:" has a Revision Number (":[[LastCommitted]]:") AFTER this Releases Revision # ":[[RevisionNumber]]:" ! (one-off Commit ?)"
    end
  next N.R.L
  crt
return

[[DisplayErrors]]:
  if Err # '' then
    crt
    crt 'ERROR ! : ':Err<1>
    [[NumErrs]] = dcount(Err, @FM)
    for N.E = 2 to [[NumErrs]]
      crt '          ':Err<N.E>
    next N.E
    crt
    crt "   ('SVN -H' for more info)"
    crt
  end
return

[[ReadRelease]]:
  [[ReleaseLocation]] = ''
  flistPath = "/home/release/":[[ReleaseNumber]]:"/flist"
  call READ.UNIX( [[ReleaseText]], flistPath, Err)
  if Err # '' then
    [[ReleaseLocation]] = ' ** RELEASED **'
    flistPath = "/home/release/released/":[[ReleaseNumber]]:"/flist"
    call READ.UNIX( [[ReleaseText]], flistPath, Err2)
    if Err2 # '' then
      crt Err ; crt Err2 ; input j ; return
    end
    Err = ''  ;*  Must be in 'released'... so we're good.
  end

  convert char(10):char(13) to @FM in [[ReleaseText]]
  [[SvnLine]] = 0 ;* Track the 'SVN:' line to append the # if we are Committing and there's not one already
  [[NumLines]] = dcount( [[ReleaseText]], @FM )
  for N.L = 1 to [[NumLines]]
    LN = trim( [[ReleaseText]]<N.L> )
    begin case
      case LN[1,2] = '**' and [[CommitComment]] = ''
        [[CommitComment]] = LN[3, 99999]       ;*  Special single comment line used for Commit
      case LN[1,1] = '*' or LN[1,1] = '#'  ;*  Ignore comments
      case index(LN, ':', 1) # 0           ;*  Handle special tags :
        if LN[1,4] = "SVN:" then           ;*  Is this the "SVN:" line ?
          [[SvnLine]] = N.L                    ;*  Remember where
        end
      case LN # ''                         ;*  Finally handle normal lines:
        Item = LN ; gosub [[AddItem]]
    end case
  next N.L
return

[[AddItem]]:
  [[FileName]] = field(Item, '/', 1) ; [[ItemID]] = field(Item, '/', 2)
  open [[FileName]] to File then
    [[FileList]] := Item:' '  ;*  Keep list because some things don't need to be in UV ?:
    read dummy from File, [[ItemID]] else
      [[FileErrs]]<-1> = [[ItemID]]:" is not in ":[[FileName]]
    end
  end else
    if [[FileName]] = 'DICT' then  ;*  Special case: make it act like a BP ?
      [[FileList]] := Item:' '     ;*  Just like above ?
    end else
      [[FileErrs]]<-1> = [[FileName]]:" is not a valid BP file/directory."
    end
  end
return

[[GetCommitComment]]:
  * Add spaces, to allow for the "new" comment to be longer than '[[CommitComment]]'. A MR.IN characteristic.
  commitLength = len([[CommitComment]])
  [[DisplayComment]] = [[CommitComment]]:spaces(100-commitLength)
  crt "Enter comment:": ; call MR.IN( [[DisplayComment]], '', OUT )
  if OUT = "ESC" or OUT = 'HOME' then stop
  [[CommitComment]] = trim([[DisplayComment]])
return

* =======================================================================================

*  Set all Option flags and set [[FileList]] and [[FileErrs]]. Note we don't handle the errors
*  now because some options don't require them anyway.

[[ParseCommandLine]]:
  [[CmdLineOptions]] = "SINGLEPARAM"  ;*  for -M option
  call PARSE.CMDLINE( @SENTENCE, mat CMDLINE, [[CmdLineOptions]] )
  if CMD.HELP then gosub Help ; stop
  svnOp = CMD.ARG.S<1, 1>
  [[FileName]] = CMD.ARG.S<1, 2>
  locate 'D' in CMD.FLAG.S<1> setting dum then [[DisplayCmd]] = @TRUE else [[DisplayCmd]] = @FALSE
  locate 'L' in CMD.FLAG.S<1> setting [[SelectListLoc]] then
    [[SelectListName]] = CMD.PARAM.S<1, [[SelectListLoc]], 1>
  end else [[SelectListName]] = ''
  locate 'N' in CMD.FLAG.S<1> setting dum then [[NoExecute]] = @TRUE else [[NoExecute]] = @FALSE
  locate 'M' in CMD.FLAG.S<1> setting [[MessagePos]] then
    [[CommitComment]] = CMD.PARAM.S<1, [[MessagePos]], 1>   ;*  'SINGLEPARAM' is set so there's only one line
  end else [[CommitComment]] = ''
  locate 'R' in CMD.FLAG.S<1> setting [[ReleasePos]] then
    [[ReleaseNumber]] = CMD.PARAM.S<1, [[ReleasePos]], 1>
  end else [[ReleaseNumber]] = ''
  locate 'V' in CMD.FLAG.S<1> setting dum then Verbose = @TRUE else Verbose = @FALSE
  locate 'P' in CMD.FLAG.S<1> setting [[PropertyNameAndValueLoc]] then
    [[PropertyNameAndValue]] = CMD.PARAM.S<1, [[PropertyNameAndValueLoc]], 1>
  end else [[PropertyNameAndValue]] = ''
  [[FileList]]  = ""  ;*  Space separated; each item is a path from /u/dsisrc :
  [[FileErrs]]  = ""

  begin case      ;*  Lots of ways to get the [[FileList]]:
    case [[ReleaseNumber]]  # '' ; gosub [[ReadRelease]]
    case [[SelectListName]] # '' ;* Use the SELECT list if provided
      getlist [[SelectListName]] else Err = "Unable to read Select List ": [[SelectListName]] ; return
      loop while readnext [[ItemID]] do
        Item = [[FileName]]:'/':[[ItemID]] ; gosub [[AddItem]]
      repeat
    case 1   ;* Get the individual files if no "-L" option was specified
      for N.A = 3 to CMD.NUM.ARGS   ;* We get the files as arguments 3 and more
        Item = [[FileName]]:'/':CMD.ARG.S<1,N.A> ; gosub [[AddItem]]
      next N.A
  end case

  if svnOp = '' then gosub Help
return

Help:
  crt 'SVN <command> { <BP_Dir> <item> ... | -L <save-list> | -R <release#> } [-N][-M "message"][-V][-D][-P <[[PropName]]=PropVal>]'
  crt
  crt " where <command> is COMPILE, COMMIT, ADD, DELETE, DIFF, INFO, LOG, REVERT, STATUS, HELP, PROPSET. Options:"
  crt "  -N : No Execute; for testing just to see the <command>"
  crt "  -V : Verbose for STATUS; default for listed items; NOT default for 'all' option"
  crt "  -D : Display the <command> before executing it."
  crt "  -P : Add more arguments after <command>, useful for PROPSET (example)"
  crt
  crt " For 'COMMIT' when 'M is not used, you will be prompted for a comment if the release has no '**' comment."
  crt
  crt "Examples:"
  crt "  SVN COMMIT DSI.BP AR.FREEZE AR.UNFREEZE"
  crt "  SVN COMMIT DSI.BP -L DSI.BP.FLIST"
  crt "  SVN COMMIT -R 570                    : Commit EVERY program in Release 570 using the '**' line for the Comment"
  crt "  SVN COMPILE -R 570                   : Compile EVERY program in Release 570: NOT REALLY SVN but it's handy!"
  crt "  SVN LISTS   -R 570                   : Save Select Lists for program files: NOT REALLY SVN but it's handy!"
  crt "  SVN STATUS DSI.BP                    : Show all uncommitted 'M'odifications, 'D'eletes, 'A'dds, etc."
  crt "  SVN DIFF DSI.BP AR.FREEZE            : Show the difference between the local copy and what's in SVN"
  crt "  SVN INFO DSI.BP AR.FREEZE PMTS       : Show misc info about what's in SVN"
  crt "  SVN CLEANUP /u/dsisrc[[/DSI]].BP         : Execute cleanup on DSI.BP directory (if something is locked, etc)"
  crt "  SVN LOG DSI.BP AR.FREEZE             : List of historical changes"
  crt
  crt "To add a new file, you need to execute ADD first before Committing (i.e. standard 'svn' procedure):"
  crt "  SVN ADD    DSI.BP NEWFILENAME"
  crt "  SVN COMMIT DSI.BP NEWFILENAME"
  crt
  crt "To delete a file, you need to execute DELETE first, and then 'commit the delete' (again, standard svn):"
  crt "(note: this can be used if you get 'Already Exists' errors ? Just backup your files first !)"
  crt "  SVN DELETE DSI.BP ANYFILENAME"
  crt "  SVN COMMIT DSI.BP ANYFILENAME"
  crt
  crt "To set properties like svn:keywords: "
  crt "  SVN PROPSET DSI.BP ANYFILENAME -P svn:keywords=Id"   
  crt "  SVN PROPSET DSI.BP ANYFILENAME -P svn:keywords=Id Rev Date Author URL"
  crt
  crt "To FIX SVN if you get 'Out of Date' errors (!?) :"
  crt "  SVN UPDATE -R 570                    : UPDATE EVERY program in Release 570 to the current SVN #"
  crt "                                         (CAN THIS OVERWRITE YOUR CHANGES !?)"
  crt
  crt "For more svn options try: svn -help and svn <command> help"
  crt "(see also Confluence page: http://intranet.docmagic.com/display/Development/Universe+SVN+Integration)"
return