001package org.vishia.guiBzr;
002
003import java.io.BufferedReader;
004import java.io.File;
005import java.io.FileNotFoundException;
006import java.io.FileReader;
007import java.io.IOException;
008import java.text.DateFormat;
009import java.text.SimpleDateFormat;
010import java.util.LinkedList;
011import java.util.List;
012
013import org.vishia.mainCmd.MainCmd_ifc;
014import org.vishia.mainCmd.Report;
015import org.vishia.util.FileSystem;
016
017public class BzrGetStatus
018{
019
020  /**TODO only private local using here, it should be a part of DataProject.
021   * 
022   */
023  List<File> listBzrDirs = new LinkedList<File>();
024  
025  final MainData mainData;
026  
027  final MainCmd_ifc mainCmdifc;
028  
029  /**The format of a timestamp in the log output. */
030  private final DateFormat logDateFormat= new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
031  
032  
033  private final List<DataFile> listUnknownFiles = new LinkedList<DataFile>();
034  
035  public BzrGetStatus(MainCmd_ifc mainCmdifc, MainData mainData)
036  { this.mainCmdifc = mainCmdifc;
037    this.mainData = mainData;
038  }
039
040
041
042  /**Searches all locations of source-archives in the current project folder and all sub folders.
043   * A project means a software project with some sources consisting of some Components with its own archives.
044   * @calls {@link #captureStatus(DataCmpn)} for all found software-archives.
045   * @param sProjectPath Path to the project folder.
046   * 
047   */
048  void getBzrLocations(String sProjectPath)
049  {
050    listBzrDirs.clear();
051    try{ FileSystem.addFileToList(sProjectPath + "/**/.bzr", listBzrDirs);
052    } catch(Exception exc){ }
053    int zCmpn = listBzrDirs.size();
054    mainData.currPrj.init(zCmpn);
055    //int ixCmpn = 0;
056    for(File fileBzr: listBzrDirs){
057      File bzrLocation = fileBzr.getParentFile();
058      int ixCmpn = mainData.currPrj.createComponentsData(bzrLocation);
059      ixCmpn +=1;
060    }
061  }
062  
063  
064  
065  /**Captures the status of a software archive of one component in comparison of its real source files.
066   * <ul>
067   * <li>last revision of files, last revision in archive, number and timestamp
068   * <li>get status
069   * </ul>
070   * It fills the indexed instance of {@link DataCmpn}
071   * @param ixData The index of the component, index in data
072   */
073  void captureStatus(DataCmpn data)
074  {
075    //DataCmpn data = mainData.currPrj.data[ixData];    
076    data.uBzrError.setLength(0);
077    data.uBzrLastVersion.setLength(0);
078    data.uBzrStatusOutput.setLength(0);
079    mainData.cmdExec.setCurrentDir(data.dirWorkingtree);
080    String sCmdStatus = mainData.cfg.indexCmds.get("status");
081    String sCmdheadRevision = mainData.cfg.indexCmds.get("headRevision");
082    mainCmdifc.writeInfo(sCmdStatus);
083    mainData.cmdExec.execute(sCmdStatus, null, data.uBzrStatusOutput, data.uBzrError);
084    mainCmdifc.writeInfo(sCmdheadRevision);
085    mainData.cmdExec.execute(sCmdheadRevision, null, data.uBzrLastVersion, data.uBzrError);
086    mainCmdifc.writeInfo(" done.\n");
087    getVersionFromLogOutput(data.uBzrLastVersion, data, data.revisionWorkingTreeTop);
088    File fileBzrVersion = new File(data.dirWorkingtree, "_bzrVersion.txt");
089    if(fileBzrVersion.exists()){ 
090      String lastLogfile = FileSystem.readFile(fileBzrVersion);
091      StringBuilder uLog = new StringBuilder(lastLogfile);
092      getVersionFromLogOutput(uLog, data, data.revisionSbox);
093    }
094  }
095  
096  
097  
098  void captureStatusAllArchives(DataCmpn data){
099    captureStatus(data);
100    //
101    data.uBzrLastVersion.setLength(0);
102    String sCmdheadRevision = mainData.cfg.indexCmds.get("headRevision");
103    
104    mainCmdifc.writeInfoln(sCmdheadRevision + " archive");
105    mainData.cmdExec.setCurrentDir(data.dirArchive);
106    mainData.cmdExec.execute(sCmdheadRevision, null, data.uBzrLastVersion, data.uBzrError);
107    getVersionFromLogOutput(data.uBzrLastVersion, data, data.revisionArchive);
108    if(data.dirRemoteArchive !=null){
109      mainCmdifc.writeInfoln(sCmdheadRevision + " remote archive");
110      mainData.cmdExec.setCurrentDir(data.dirRemoteArchive);
111      mainData.cmdExec.execute(sCmdheadRevision, null, data.uBzrLastVersion, data.uBzrError);
112      getVersionFromLogOutput(data.uBzrLastVersion, data, data.revisionRemoteArchive);
113    }
114      
115  }
116  
117  
118  
119  
120  /**Reads the status output and fills the {@link #listUnknownFiles},
121   * {@link DataCmpn#listModifiedFiles}, {@link DataCmpn#listNewFiles}, 
122   * {@link DataCmpn#listAddFiles}, {@link DataCmpn#listRemovedFiles}, 
123   * 
124   */
125  void initListFiles()
126  {
127    DataCmpn data = mainData.currCmpn;
128    StringBuilder uStatus = data.uBzrStatusOutput;
129    String sLine;
130    listUnknownFiles.clear();
131    List<DataFile> listFiles = listUnknownFiles;
132    String sType = "?";
133    int posLine = 0, posLineEnd;
134    int pos;
135    data.listAddFiles = null;
136    data.listModifiedFiles = null;
137    data.listNewFiles = null;
138    data.listRemovedFiles = null;
139    data.listRenamedFiles = null;
140    data.indexFiles.clear();
141    
142    while( (posLineEnd = uStatus.indexOf("\n", posLine))>=0){
143      sLine = uStatus.substring(posLine, posLineEnd);
144      if( (pos = sLine.indexOf("modified:"))>=0){
145        listFiles = data.listModifiedFiles = new LinkedList<DataFile>();
146        sType = "chg";
147      } else if( (pos = sLine.indexOf("unknown:"))>=0){
148        listFiles = data.listNewFiles = new LinkedList<DataFile>();
149        sType = "new";
150      } else if( (pos = sLine.indexOf("removed:"))>=0){
151        listFiles = data.listRemovedFiles = new LinkedList<DataFile>();
152        sType = "del";
153      } else if( (pos = sLine.indexOf("added:"))>=0){
154        listFiles = data.listAddFiles = new LinkedList<DataFile>();
155        sType = "add";
156      } else if( (pos = sLine.indexOf("renamed:"))>=0){
157        listFiles = data.listRenamedFiles = new LinkedList<DataFile>();
158        sType = "mov";
159      } else {
160        //line with a file path
161        String sFilePath = sLine.trim();
162        if(sFilePath.endsWith("*")){
163          sFilePath = sFilePath.substring(0, sFilePath.length()-1).trim();
164        }
165        int posSep = sFilePath.indexOf("=>");
166        if( posSep >=0){
167          sFilePath = sFilePath.substring(posSep+2).trim();
168        }
169        sFilePath = sFilePath.replace('\\', '/');
170        File file = new File(mainData.currCmpn.dirWorkingtree, sFilePath);
171        DataFile fileData = new DataFile(file, sFilePath, sType);
172        listFiles.add(fileData);
173        data.indexFiles.put(sFilePath, fileData);
174      }
175      posLine = posLineEnd +1;    
176    }
177    
178  }
179  
180  
181  
182  void getVersionFromLogOutput(StringBuilder uLog, DataCmpn data, DataCmpn.Revision revision)
183  {
184    
185    try{ 
186      String sLine;
187      int posLine = 0, posLineEnd;
188      int pos;
189      boolean bRevnrOk = false, bRevDateOk = false;
190      while( (!bRevnrOk || !bRevDateOk) && (posLineEnd = uLog.indexOf("\n", posLine))>=0){
191        sLine = uLog.substring(posLine, posLineEnd);
192        if( (pos = sLine.indexOf("revno:"))>=0){
193          //line: revno: <#?revision>
194          String sRevision = sLine.substring(pos + 6).trim();
195          //int nrRev = Integer.parseInt(sRevision);
196          revision.nr = sRevision;
197          bRevnrOk = true;
198        } else if( (pos = sLine.indexOf("timestamp:"))>=0){
199          //line: timestamp: <timestamp>
200          String sDate = sLine.substring(pos + 15, pos+34).trim();
201          long dateVersion = logDateFormat.parse(sDate).getTime();
202          revision.date = dateVersion;
203          bRevDateOk = true;
204        }
205        posLine = posLineEnd +1;    
206      }
207    } catch(Exception exc){ throw new RuntimeException(exc); }
208  }
209}