00001
00002
00003
00004
00005
00006
00007
00008
00009
00011
00012
00013
00014 #include "wx/wxprec.h"
00015
00016 #ifdef __BORLANDC__
00017 #pragma hdrstop
00018 #endif
00019
00020 #ifndef WX_PRECOMP
00021 #include "wx/wx.h"
00022 #endif
00023
00024
00025 #include <wx/fileconf.h>
00026 #include <wx/filename.h>
00027 #include <wx/ptr_scpd.h>
00028 #include <wx/dir.h>
00029
00030
00031 #include <wx/zipstrm.h>
00032 #include <wx/wfstream.h>
00033 #include <wx/tarstrm.h>
00034 #include <wx/mstream.h>
00035 #include <wx/txtstrm.h>
00036 #include <wx/zstream.h>
00037
00038 #include <wx/protocol/ftp.h>
00039
00040 #include "wxp/package.h"
00041 #include "wxp/wxp.h"
00042 #include "wxp/packagewxp.h"
00043 #include "wxp/wxbuild.h"
00044
00045 #include <memory>
00046 using namespace std;
00047
00048
00049 wxArrayString wxPackage::s_arrLocalRepo;
00050 wxArrayString wxPackage::s_arrRemoteRepo;
00051
00052
00053
00054 wxString wxPackageStatusName[] =
00055 {
00056 _("Remote"),
00057 _("Downloaded"),
00058 _("Decompressed"),
00059 _("Built"),
00060 _("Installed")
00061 };
00062
00063
00064
00065 IMPLEMENT_DYNAMIC_CLASS(wxPackage, wxObject)
00066
00067
00068 #include <wx/arrimpl.cpp> // this is a magic incantation which must be done!
00069 WX_DEFINE_OBJARRAY(wxPackageArrayHelper);
00070
00071
00072 wxPackage wxEmptyPackage;
00073 wxPackageArray wxEmptyPackageArray;
00074
00075
00076
00077
00078
00079
00080
00081 wxIMPLEMENT_STRING2ENUM(PackageStatus, wxPS_MAX)
00082
00083
00084
00085
00086
00087
00088
00089 bool wxPackage::IsOk() const
00090 {
00091 if (!wxPackageInfo::IsOk())
00092 return false;
00093
00094
00095
00096 switch (m_status)
00097 {
00098 case wxPS_INSTALLED:
00099 if (!wxFileName::DirExists(m_strInstallationPath))
00100 return false;
00101
00102
00103 case wxPS_DECOMPRESSED:
00104 if (m_strWXPPath.IsEmpty() || !wxFileName(m_strWXPPath).IsRelative())
00105 return false;
00106 if (!wxFileName::DirExists(m_strDecompressionPath))
00107 return false;
00108
00109
00110 case wxPS_DOWNLOADED:
00111 if (!wxFileName::FileExists(m_strDownloadPath))
00112 return false;
00113
00114
00115 case wxPS_REMOTE:
00116 break;
00117
00118 default:
00119 return true;
00120 }
00121
00122 return true;
00123 }
00124
00125 void wxPackage::DoUpdateSubstitutionHashMap(wxPackageSubstituteInfoContext ctx)
00126 {
00127 wxPackageInfo::DoUpdateSubstitutionHashMap(ctx);
00128
00129 wxStringHashMap &keywords = m_hashmapSubstitution[ctx];
00130
00131 #define ADD_KEYWORD(name, value) \
00132 keywords[wxT(name)] = value
00133
00134 ADD_KEYWORD("packageroot", m_strDecompressionPath);
00135
00136 switch (m_status)
00137 {
00138 case wxPS_REMOTE:
00139 if (!GetDownloadLink().IsEmpty())
00140 ADD_KEYWORD("location", GetDownloadLink());
00141 else
00142 ADD_KEYWORD("location", wxT("not available"));
00143 break;
00144
00145 case wxPS_DOWNLOADED:
00146 ADD_KEYWORD("location", m_strDownloadPath);
00147 break;
00148 case wxPS_DECOMPRESSED:
00149 case wxPS_BUILT:
00150 case wxPS_INSTALLED:
00151 ADD_KEYWORD("location", m_strDecompressionPath);
00152 break;
00153
00154 default:
00155 ADD_KEYWORD("location", wxT("not available"));
00156 }
00157
00158
00159 wxStringHashMap compiler =
00160 m_compiler.GetSubstitutionHashMap(m_buildSystemType);
00161 wxMergeHashMap(keywords, compiler);
00162 }
00163
00164 wxPackageCommand wxPackage::GetCmd(const wxPackageCommand &cmd,
00165 wxPackageBuildSystemStage stage,
00166 long flags,
00167 const wxPackageCondition &cond) const
00168 {
00169
00170 wxPackageCommand ret(wxPackageInfo::GetCmd(cmd, stage, flags, cond));
00171
00172
00173 wxString subst = SubstituteInfo(ret.GetCommand());
00174 ret.SetCommand(subst);
00175
00176 #ifdef __WXDEBUG__
00177
00178 if (subst.Contains(wxWPM_SUBSTITUTION_START_MARKER))
00179 wxLogDebug(wxT("wxPackage::GetCmd - found unknown keywords in the command: [%s]"),
00180 subst.c_str());
00181 #endif
00182
00183 return ret;
00184 }
00185
00186 void wxPackage::SetRemoteStatus(const wxString &downloadpath)
00187 {
00188 m_status = wxPS_REMOTE;
00189
00190
00191 if (!downloadpath.IsEmpty())
00192 {
00193 wxFileName fn(downloadpath);
00194 wxASSERT(!fn.IsDir() && fn.IsAbsolute());
00195 m_strDownloadPath = fn.GetFullPath();
00196 }
00197 else
00198 m_strDownloadPath = wxEmptyString;
00199
00200 UpdatePackageInfo();
00201 }
00202
00203 void wxPackage::SetDownloadedStatus(const wxString &downloadpath)
00204 {
00205 wxFileName dp(downloadpath);
00206
00207
00208 wxASSERT(!dp.IsDir() && dp.IsAbsolute());
00209
00210 m_status = wxPS_DOWNLOADED;
00211 m_strDownloadPath = dp.GetFullPath();
00212
00213 UpdatePackageInfo();
00214 }
00215
00216 void wxPackage::SetDecompressedStatus(const wxString &decompresspath)
00217 {
00218 wxFileName dp = wxFileName::DirName(decompresspath);
00219
00220
00221 wxASSERT(dp.IsDir() && dp.IsAbsolute());
00222
00223 m_status = wxPS_DECOMPRESSED;
00224 m_strDecompressionPath = dp.GetPath();
00225
00226 UpdatePackageInfo();
00227 }
00228
00229 void wxPackage::SetBuiltStatus()
00230 {
00231 m_status = wxPS_BUILT;
00232 UpdatePackageInfo();
00233 }
00234
00235 void wxPackage::SetInstalledStatus(const wxString &installpath)
00236 {
00237 m_status = wxPS_INSTALLED;
00238 m_strInstallationPath = installpath;
00239
00240 UpdatePackageInfo();
00241 }
00242
00243 void wxPackage::UpdatePackageInfo()
00244 {
00245 if (m_status >= wxPS_DECOMPRESSED)
00246 {
00247
00248 m_refLogo.ExpandLocalRef(m_strDecompressionPath);
00249 for (size_t i=0; i < m_arrScreenshots.GetCount(); i++)
00250 m_arrScreenshots[i].ExpandLocalRef(m_strDecompressionPath);
00251 for (size_t i=0; i < m_arrDocumentation.GetCount(); i++)
00252 m_arrDocumentation[i].ExpandLocalRef(m_strDecompressionPath);
00253
00254 UpdateCompressedSize();
00255 UpdateMD5();
00256 }
00257 else if (m_status >= wxPS_DOWNLOADED)
00258 {
00259
00260
00261
00262 m_refLogo.ExpandLocalRefToWXZRef(m_strDownloadPath);
00263 for (size_t i=0; i < m_arrScreenshots.GetCount(); i++)
00264 m_arrScreenshots[i].ExpandLocalRefToWXZRef(m_strDownloadPath);
00265 for (size_t i=0; i < m_arrDocumentation.GetCount(); i++)
00266 m_arrDocumentation[i].ExpandLocalRefToWXZRef(m_strDownloadPath);
00267
00268 UpdateCompressedSize();
00269 UpdateMD5();
00270 }
00271 else if (m_status == wxPS_REMOTE)
00272 {
00273
00274 m_refLogo.RemoveLocalRef();
00275 for (size_t i=0; i < m_arrScreenshots.GetCount(); i++)
00276 m_arrScreenshots[i].RemoveLocalRef();
00277 for (size_t i=0; i < m_arrDocumentation.GetCount(); i++)
00278 m_arrDocumentation[i].RemoveLocalRef();
00279 }
00280 }
00281
00282 bool wxPackage::LoadStatusInfo(wxConfigBase *cfg, const wxString &path)
00283 {
00284 if (!cfg->Read(path + wxT("/Status"), (long *)&m_status))
00285 return false;
00286
00287
00288
00289
00290
00291
00292 if (m_status == wxPS_REMOTE)
00293 {
00294
00295 if (!m_strDownloadPath.IsEmpty() &&
00296 wxFileName::FileExists(m_strDownloadPath))
00297 m_status = wxPS_DOWNLOADED;
00298 }
00299
00300 if (m_status != wxPS_DOWNLOADED &&
00301 m_status != wxPS_DECOMPRESSED &&
00302 m_status != wxPS_BUILT &&
00303 m_status != wxPS_INSTALLED)
00304 return false;
00305
00306
00307 wxString str;
00308 if (!cfg->Read(path + wxT("/DownloadPath"), &str))
00309 return false;
00310
00311
00312
00313 if (!str.IsEmpty())
00314 m_strDownloadPath = str;
00315
00316 if (!cfg->Read(path + wxT("/WXPPath"), &m_strWXPPath))
00317 return false;
00318 if (m_status >= wxPS_DECOMPRESSED &&
00319 !cfg->Read(path + wxT("/DecompressionPath"), &m_strDecompressionPath))
00320 return false;
00321 if (m_status >= wxPS_INSTALLED &&
00322 !cfg->Read(path + wxT("/InstallationPath"), &m_strInstallationPath))
00323 return false;
00324
00325
00326 if (m_status >= wxPS_DOWNLOADED && !wxFileName::FileExists(m_strDownloadPath))
00327 {
00328 wxLogWarning(_("The package %s %s is marked as downloaded but\n\t%s\ndoes not exist. Resetting it to the not-downloaded-yet package status."),
00329 GetName().c_str(), GetVersion().GetAsString().c_str(), m_strDownloadPath.c_str());
00330 m_status = wxPS_REMOTE;
00331 m_strDownloadPath = wxEmptyString;
00332 }
00333
00334 if (m_status >= wxPS_DECOMPRESSED)
00335 {
00336 if (!wxFileName::DirExists(m_strDecompressionPath))
00337 {
00338 wxLogWarning(_("The package %s %s is marked as decompressed but the folder\n\t%s\ndoes not exist. Resetting it to the just-downloaded package status."),
00339 GetName().c_str(), GetVersion().GetAsString().c_str(), m_strDecompressionPath.c_str());
00340 m_status = wxPS_DOWNLOADED;
00341 m_strDecompressionPath = wxEmptyString;
00342 }
00343 else if (!wxFileName::FileExists(GetAbsWXPPath()))
00344 {
00345 wxLogWarning(_("The package %s %s is marked as decompressed in the folder\n\t%s\nbut the file\n\t%s\ndoes not exist. Resetting it to the just-downloaded package status."),
00346 GetName().c_str(), GetVersion().GetAsString().c_str(), m_strDecompressionPath.c_str(),
00347 GetAbsWXPPath().c_str());
00348 m_status = wxPS_DOWNLOADED;
00349 m_strDecompressionPath = wxEmptyString;
00350 }
00351 else
00352 {
00353
00354
00355
00356
00357
00358
00359 }
00360 }
00361
00362
00363
00364
00365 UpdatePackageInfo();
00366
00367 return true;
00368 }
00369
00370 bool wxPackage::SaveStatusInfo(wxConfigBase *cfg, const wxString &path) const
00371 {
00372 cfg->Write(path + wxT("/Status"), m_status);
00373
00374 cfg->Write(path + wxT("/DownloadPath"), m_strDownloadPath);
00375 cfg->Write(path + wxT("/DecompressionPath"), m_strDecompressionPath);
00376 cfg->Write(path + wxT("/InstallationPath"), m_strInstallationPath);
00377 cfg->Write(path + wxT("/WXPPath"), m_strWXPPath);
00378
00379 return true;
00380 }
00381
00382 wxULongLong wxPackage::GetDecompressedSize() const
00383 {
00384 wxCHECK_MSG(m_status >= wxPS_DOWNLOADED, 0, wxT("Invalid package status"));
00385 wxULongLong ret;
00386
00387
00388 auto_ptr<wxArchiveInputStream> arc( GetInputStream(GetDownloadPath()) );
00389 auto_ptr<wxArchiveEntry> entry;
00390
00391 if (arc.get() == NULL)
00392 return false;
00393
00394 while (entry.reset(arc->GetNextEntry()), entry.get() != NULL)
00395 ret += entry->GetSize();
00396
00397 return ret;
00398 }
00399
00400 wxWidgetsBuildArray wxPackage::GetSupportedWxBuilds(bool docompilercheck) const
00401 {
00402 wxWidgetsBuildArray ret;
00403 for (size_t i=0; i < wxWidgetsBuildArray::s_arrWxBuilds.GetCount(); i++)
00404 {
00405 const wxWidgetsBuild &b = wxWidgetsBuildArray::s_arrWxBuilds[i];
00406
00407
00408 if (!SupportsWxPort(b.GetPortId(), b.GetVersion()))
00409 continue;
00410
00411 if (docompilercheck)
00412 if (b.GetCompilerUsed() != m_compiler.GetSelFormat())
00413 continue;
00414
00415
00416 ret.Add(b);
00417 }
00418
00419 return ret;
00420 }
00421
00422 bool wxPackage::GetRecursiveDependencies(wxPackageDependencyArray *ret,
00423 const wxPackageArray &arr,
00424 wxPackageDependencyType type,
00425 wxPackageDependencyArray *notfound) const
00426 {
00427 static wxPackageIdArray s_temp;
00428 s_temp.Clear();
00429
00430 if (!DoGetRecursiveDependencies(ret, arr, type, notfound, &s_temp))
00431 {
00432
00433 if (notfound)
00434 {
00435
00436
00437
00438 for (size_t i=0; i<notfound->GetCount(); i++)
00439 {
00440 int n = ret->Index(notfound->Item(i));
00441 wxASSERT(n != wxNOT_FOUND);
00442 ret->RemoveAt(n);
00443 }
00444 }
00445
00446 return false;
00447 }
00448
00449 return true;
00450 }
00451
00452 bool wxPackage::DoGetRecursiveDependencies(wxPackageDependencyArray *ret,
00453 const wxPackageArray &arr,
00454 wxPackageDependencyType type,
00455 wxPackageDependencyArray *notfound,
00456 wxPackageIdArray *alreadyprocessed) const
00457 {
00458
00459 wxASSERT(ret && alreadyprocessed);
00460
00461 if (alreadyprocessed->Index(*this) != wxNOT_FOUND)
00462 {
00463
00464
00465 return true;
00466 }
00467
00468
00469 wxPackageDependencyArray temp;
00470 const wxPackageDependencyArray *toadd;
00471 if (type == wxPDT_INVALID)
00472 {
00473 toadd = &m_arrDependencies;
00474 }
00475 else
00476 {
00477
00478
00479 temp = m_arrDependencies.GetDependenciesOfType(type);
00480 toadd = &temp;
00481 }
00482
00483 for (size_t i=0; i < toadd->GetCount(); i++)
00484 {
00485 int n = ret->Index(toadd->Item(i));
00486 if (n != wxNOT_FOUND)
00487 {
00488 ret->Item(n).AddOwnerId(*this);
00489 continue;
00490 }
00491
00492
00493 wxASSERT(toadd->Item(i).GetOwnersId().Index(*this) != wxNOT_FOUND);
00494 ret->Add(toadd->Item(i));
00495 }
00496
00497
00498
00499
00500 alreadyprocessed->Add(*this);
00501
00502
00503 return m_arrDependencies.DoGetRecursiveDependencies(ret, arr, type, notfound, alreadyprocessed);
00504 }
00505
00506 wxArchiveInputStream *wxPackage::GetInputStream(const wxString &wxzpath) const
00507 {
00508 wxFileName fn(wxzpath);
00509 if (!fn.IsAbsolute())
00510 fn.MakeAbsolute();
00511 wxString filename = fn.GetFullPath();
00512
00513
00514
00515
00516 auto_ptr<wxInputStream> in(new wxFFileInputStream(filename));
00517
00518
00519
00520 if (fn.GetExt().CmpNoCase(wxT("wxz")) == 0)
00521 {
00522
00523 wxByte signature[12];
00524 if (!in->Read(signature, 10*sizeof(wxByte)))
00525 return NULL;
00526
00527
00528 in->SeekI(0, wxFromStart);
00529
00530 struct
00531 {
00532 wxByte magic[4];
00533 size_t nByteLen;
00534 wxPackageCompressionMode compression;
00535 } magics[2] =
00536 {
00537 {
00538 { 0x50, 0x4B, 0x03, 0x04 },
00539 4,
00540 wxPCM_ZIP
00541 },
00542 {
00543 { 0x1F, 0x8B, 0x08 },
00544 3,
00545 wxPCM_TAR_GZ
00546 }
00547 };
00548
00549 wxPackageCompressionMode detected = wxPCM_INVALID;
00550 for (size_t i=0; i < WXSIZEOF(magics); i++)
00551 {
00552 bool match = true;
00553 for (size_t j=0; j < magics[i].nByteLen; j++)
00554 match &= (signature[j] == magics[i].magic[j]);
00555
00556 if (match)
00557 {
00558 detected = magics[i].compression;
00559 break;
00560 }
00561 }
00562
00563 switch (detected)
00564 {
00565 case wxPCM_ZIP:
00566
00567 return new wxZipInputStream(in.release());
00568
00569
00570 case wxPCM_TAR_GZ:
00571 {
00572
00573 wxZlibInputStream *filter = new wxZlibInputStream(in.release());
00574 return new wxTarInputStream(filter);
00575 }
00576
00577 case wxPCM_INVALID:
00578 default:
00579 wxLogError(wxT("The archive '%s' is of unknown type."), wxzpath.c_str());
00580 return NULL;
00581 }
00582 }
00583
00584
00585 const wxFilterClassFactory *fcf;
00586 fcf = wxFilterClassFactory::Find(filename, wxSTREAM_FILEEXT);
00587 if (fcf)
00588 {
00589 in.reset(fcf->NewStream(in.release()));
00590
00591
00592 filename = fcf->PopExtension(filename);
00593 }
00594
00595
00596
00597 const wxArchiveClassFactory *acf;
00598 acf = wxArchiveClassFactory::Find(filename, wxSTREAM_FILEEXT);
00599 if (!acf)
00600 {
00601 wxLogError(wxT("The archive '%s' is of unknown type."), wxzpath.c_str());
00602 return NULL;
00603 }
00604
00605 return acf->NewStream(in.release());
00606 }
00607
00608 bool wxPackage::LoadCompressedPackage(const wxString &wxzpath)
00609 {
00610 auto_ptr<wxArchiveInputStream> arc( GetInputStream(wxzpath) );
00611 auto_ptr<wxArchiveEntry> entry;
00612
00613 if (arc.get() == NULL)
00614 return false;
00615
00616
00617 while (entry.reset(arc->GetNextEntry()), entry.get() != NULL)
00618 {
00619 wxString name = entry->GetName();
00620 if (name.EndsWith(wxT(".wxp")))
00621 {
00622 wxPackageXMLDescriptor wxp;
00623 if (!wxp.Load(*arc))
00624 return false;
00625
00626
00627 *this = wxp.GetPackageInfo();
00628 if (!IsOk())
00629 {
00630 wxLogError(wxT("The WXP contained in '%s' is invalid!"),
00631 wxzpath.c_str());
00632 return false;
00633 }
00634
00635
00636 wxFileName fn(wxzpath);
00637 if (!fn.IsAbsolute())
00638 fn.MakeAbsolute();
00639
00640
00641 SetDownloadedStatus(fn.GetFullPath());
00642 SetRelativeWXPPath(name);
00643
00644
00645 return true;
00646 }
00647 }
00648
00649
00650 return false;
00651 }
00652
00653 bool wxPackage::Decompress(const wxString &dir, wxProgressHandler *progress)
00654 {
00655 wxASSERT(wxFileName(dir).IsAbsolute());
00656
00657
00658 wxString path(dir);
00659 if (path.Last() == wxFileName::GetPathSeparator())
00660 path.RemoveLast();
00661 if (!wxFileName::DirExists(path))
00662 {
00663 wxLogError(wxT("The decompression folder '%s' does not exist!"), dir.c_str());
00664 return false;
00665 }
00666
00667 wxULongLong decompressedbytes = 0,
00668 totalbytes = GetDecompressedSize();
00669
00670 auto_ptr<wxArchiveInputStream> arc( GetInputStream(GetDownloadPath()) );
00671 auto_ptr<wxArchiveEntry> entry;
00672
00673 if (arc.get() == NULL)
00674 return false;
00675
00676 while (entry.reset(arc->GetNextEntry()), entry.get() != NULL)
00677 {
00678 wxFileName fn(path + wxFileName::GetPathSeparator() + entry->GetName());
00679
00680 if (entry->IsDir())
00681 {
00682
00683 if (!fn.DirExists() && !fn.Mkdir(0777, wxPATH_MKDIR_FULL))
00684 {
00685 wxLogError(_("Cannot create folder '%s' - maybe because of a permission problem"),
00686 fn.GetFullPath().c_str());
00687 return false;
00688 }
00689 else
00690 continue;
00691 }
00692
00693
00694 wxString outpath = fn.GetFullPath();
00695 wxFileName basepath(outpath);
00696 if (!basepath.DirExists() && !basepath.Mkdir(0777, wxPATH_MKDIR_FULL))
00697 {
00698 wxLogError(_("Cannot create folder '%s' - maybe because of a permission problem"),
00699 basepath.GetPath().c_str());
00700 return false;
00701 }
00702
00703 wxFFileOutputStream out(outpath);
00704
00705
00706 out.Write(*arc);
00707 if (out.GetSize() != entry->GetSize())
00708 {
00709 wxLogError(_("An error occurred when decompressing the '%s' file.\nIt should be %d bytes long but the size of the decompressed file is %d bytes. Please check the archive's integrity."),
00710 fn.GetFullPath().c_str(), entry->GetSize(), out.GetSize());
00711 return false;
00712 }
00713
00714 decompressedbytes += entry->GetSize();
00715
00716
00717
00718 if (progress)
00719 progress->OnUpdate((int)(1000 * ( decompressedbytes.ToDouble() / totalbytes.ToDouble() )),
00720 entry->GetName());
00721 }
00722
00723 SetDecompressedStatus(path);
00724 return true;
00725 }
00726
00727
00728 class wxPackageDirTraverser : public wxDirTraverser
00729 {
00730 public:
00731 wxPackageDirTraverser(const wxString &prefix,
00732 const wxArrayString &filesToExclude,
00733 const wxArrayString &dirsToExclude,
00734 const wxArrayString &patternsToExclude,
00735 wxULongLong *totalsize)
00736 : m_prefix(prefix),
00737 m_pTotalSize(totalsize)
00738 {
00739
00740 ConvertToNativeSeparator(filesToExclude, m_arrFilesExcluded);
00741 ConvertToNativeSeparator(dirsToExclude, m_arrDirsExcluded);
00742 ConvertToNativeSeparator(patternsToExclude, m_arrPatternsExcluded);
00743 }
00744
00745 void ConvertToNativeSeparator(const wxArrayString &source, wxArrayString &arr)
00746 {
00747 const wxString sep = wxString(wxFileName::GetPathSeparator(), 1);
00748 for (size_t i=0; i<source.GetCount(); i++)
00749 {
00750 wxString str = source[i];
00751 str.Replace(wxT("/"), sep);
00752 arr.Add(str);
00753 }
00754 }
00755
00756 virtual wxDirTraverseResult OnFile(const wxString& filename)
00757 {
00758 wxASSERT(filename.StartsWith(m_prefix));
00759 wxString name = filename.Mid(m_prefix.Len());
00760
00761
00762 if (name[0] == wxFileName::GetPathSeparator())
00763 name = name.Mid(1);
00764
00765 if (m_arrFilesExcluded.Index(name) != wxNOT_FOUND)
00766 return wxDIR_CONTINUE;
00767
00768 for (size_t i=0; i<m_arrPatternsExcluded.GetCount(); i++)
00769 if (wxMatchWild(m_arrPatternsExcluded[i], name, false ))
00770 return wxDIR_CONTINUE;
00771
00772
00773 m_files.Add(filename);
00774
00775 if (m_pTotalSize)
00776 *m_pTotalSize += wxFileName::GetSize(filename);
00777
00778 return wxDIR_CONTINUE;
00779 }
00780
00781 virtual wxDirTraverseResult OnDir(const wxString& dirname)
00782 {
00783 wxASSERT(dirname.StartsWith(m_prefix));
00784 wxString name = dirname.Mid(m_prefix.Len());
00785
00786
00787 if (name[0] == wxFileName::GetPathSeparator())
00788 name = name.Mid(1);
00789
00790 if (m_arrDirsExcluded.Index(name) != wxNOT_FOUND)
00791 return wxDIR_IGNORE;
00792
00793
00794 return wxDIR_CONTINUE;
00795 }
00796
00797 wxArrayString GetFiles() const
00798 { return m_files; }
00799
00800 protected:
00801 wxString m_prefix;
00802 wxArrayString m_arrFilesExcluded,
00803 m_arrDirsExcluded,
00804 m_arrPatternsExcluded;
00805
00806 wxULongLong *m_pTotalSize;
00807
00808
00809 wxArrayString m_files;
00810 };
00811
00812 wxArrayString wxPackage::GetIncludedFiles(wxULongLong *totalsize) const
00813 {
00814
00815 wxCHECK_MSG(m_status >= wxPS_DECOMPRESSED, 0, wxT("Invalid package status"));
00816 wxString prefix = GetDecompressionPath().BeforeLast(wxFileName::GetPathSeparator());
00817
00818 wxPackageDirTraverser
00819 traverser(prefix,
00820 m_arrExcluded[wxPEM_FILE],
00821 m_arrExcluded[wxPEM_DIRECTORY],
00822 m_arrExcluded[wxPEM_PATTERN],
00823 totalsize);
00824
00825
00826 wxDir dir(GetDecompressionPath());
00827
00828 if (!dir.IsOpened())
00829 {
00830 wxArrayString empty;
00831 return empty;
00832 }
00833
00834
00835 dir.Traverse(traverser);
00836 return traverser.GetFiles();
00837 }
00838
00839
00840 class wxPackageDirTraverserArchiver : public wxDirTraverser
00841 {
00842 public:
00843 wxPackageDirTraverserArchiver(const wxString &prefix,
00844 const wxArrayString &filelist,
00845 wxArchiveOutputStream &z,
00846 wxProgressHandler *h,
00847 wxULongLong totalsize)
00848 : m_prefix(prefix), m_fileList(filelist), m_arch(z),
00849 m_progress(h), m_totalSize(totalsize)
00850 {
00851 m_bAllCompressed=true;
00852 m_compressedBytes=0;
00853 }
00854
00855 virtual wxDirTraverseResult OnFile(const wxString& filename)
00856 {
00857 if (m_fileList.Index(filename) == wxNOT_FOUND)
00858 {
00859
00860 return wxDIR_CONTINUE;
00861 }
00862
00863 wxASSERT(filename.StartsWith(m_prefix));
00864 wxString name = filename.Mid(m_prefix.Len());
00865
00866
00867 if (name[0] == wxFileName::GetPathSeparator())
00868 name = name.Mid(1);
00869
00870
00871 wxFFileInputStream in(filename);
00872
00873
00874
00875
00876
00877 wxFileName fn(filename);
00878 if (!m_arch.PutNextEntry(name, fn.GetModificationTime(), in.GetSize()))
00879 {
00880 m_bAllCompressed = false;
00881 return wxDIR_CONTINUE;
00882 }
00883
00884
00885
00886 if (m_arch.Write(in).GetLastError() != wxSTREAM_NO_ERROR)
00887 m_bAllCompressed = false;
00888 else
00889 m_compressedBytes += in.GetSize();
00890
00891
00892
00893 if (m_progress)
00894 {
00895 unsigned long progress =
00896 (int)(1000 * ( m_compressedBytes.ToDouble() / m_totalSize.ToDouble() ));
00897
00898 if (progress > 1000)
00899
00900
00901 progress = 1000;
00902
00903 m_progress->OnUpdate(progress, filename);
00904 }
00905
00906 return wxDIR_CONTINUE;
00907 }
00908
00909 virtual wxDirTraverseResult OnDir(const wxString& WXUNUSED(dirname))
00910 {
00911
00912 return wxDIR_CONTINUE;
00913 }
00914
00915 virtual wxDirTraverseResult OnOpenError(const wxString& dirname)
00916 {
00917 wxLogWarning(wxT("Couldn't compress '%s' directory: cannot open it"),
00918 dirname.c_str());
00919 m_bAllCompressed = false;
00920 return wxDIR_IGNORE;
00921 }
00922
00923 bool AllCompressed() const
00924 { return m_bAllCompressed; }
00925
00926 protected:
00927 wxString m_prefix;
00928 const wxArrayString &m_fileList;
00929
00930 wxArchiveOutputStream &m_arch;
00931 wxProgressHandler *m_progress;
00932
00933 wxULongLong m_totalSize;
00934 wxULongLong m_compressedBytes;
00935 bool m_bAllCompressed;
00936 };
00937
00938 bool wxPackage::Compress(const wxString &wxz, wxProgressHandler *progress)
00939 {
00940 wxCHECK_MSG(m_status >= wxPS_DECOMPRESSED, 0, wxT("Invalid package status"));
00941 wxString file = wxz;
00942
00943
00944 if (file.IsEmpty())
00945 file = SubstituteInfo(GetOutputFileName());
00946
00947
00948 wxFFileOutputStream out(file, wxT("wb"));
00949 if (!out.IsOk())
00950 {
00951 wxLogError(wxT("Couldn't create the output file '%s'."), wxz.c_str());
00952 return false;
00953 }
00954
00955
00956 wxArchiveOutputStream *archiveos = NULL;
00957 wxOutputStream *os = NULL;
00958 switch (GetCompressionMode())
00959 {
00960 case wxPCM_ZIP:
00961 archiveos = new wxZipOutputStream(out, wxPKG_ZIP_COMPRESSION_LEVEL);
00962 os = archiveos;
00963 break;
00964
00965 case wxPCM_TAR_GZ:
00966 if (!wxZlibOutputStream::CanHandleGZip())
00967 {
00968 wxLogError(wxT("Cannot create tar.gz archives!"));
00969 return false;
00970 }
00971
00972
00973 os = new wxZlibOutputStream(out, wxPKG_TARGZ_COMPRESSION_LEVEL, wxZLIB_GZIP);
00974 archiveos = new wxTarOutputStream(*os);
00975 break;
00976 }
00977
00978 if (!archiveos->IsOk())
00979 {
00980 wxLogError(wxT("Couldn't create the compressor output stream."));
00981 return false;
00982 }
00983
00984
00985 wxULongLong totalSz;
00986 wxArrayString filelist(GetIncludedFiles(&totalSz));
00987 if (filelist.GetCount() == 0)
00988 {
00989 wxLogError(wxT("No files to include!"));
00990 return false;
00991 }
00992
00993
00994 wxFileName prefix = wxFileName::DirName(GetDecompressionPath());
00995 prefix.RemoveLastDir();
00996
00997
00998 wxPackageDirTraverserArchiver
00999 traverser(prefix.GetPath(), filelist, *archiveos,
01000 progress, totalSz.ToULong());
01001 wxDir dir(GetDecompressionPath());
01002
01003 if (!dir.IsOpened())
01004 {
01005 wxLogError(wxT("Cannot open the directory '%s'."),
01006 GetDecompressionPath().c_str());
01007 return false;
01008 }
01009
01010
01011 dir.Traverse(traverser);
01012
01013
01014 if (!os->IsOk())
01015 {
01016 wxLogError(wxT("Cannot write to the output stream"));
01017 return false;
01018 }
01019
01020 switch (GetCompressionMode())
01021 {
01022 case wxPCM_ZIP:
01023 wxDELETE(archiveos);
01024 break;
01025
01026 case wxPCM_TAR_GZ:
01027
01028 wxDELETE(archiveos);
01029 wxDELETE(os);
01030 break;
01031 }
01032
01033 return traverser.AllCompressed() &&
01034 out.IsOk();
01035 }
01036
01037 bool wxPackage::UploadWithFTP(const wxString &u, const wxString &pass,
01038 const wxString &s, const wxString &p)
01039 {
01040 wxCHECK_MSG(m_status >= wxPS_DOWNLOADED, 0, wxT("Invalid package status"));
01041 wxString user(u), password(pass), server(s), path(p);
01042 wxURI dest(GetUploadDestination());
01043 wxFTP ftp;
01044
01045 if (user.IsEmpty())
01046 user = dest.GetUser();
01047 if (password.IsEmpty())
01048 password = dest.GetPassword();
01049 if (server.IsEmpty())
01050 server = dest.GetServer();
01051 if (path.IsEmpty())
01052 path = dest.GetPath();
01053
01054 if (!user.IsEmpty())
01055 {
01056 ftp.SetUser(user);
01057 ftp.SetPassword(password);
01058 }
01059
01060
01061 if ( !ftp.Connect(server) )
01062 {
01063 wxLogError(wxT("Couldn't connect to '%s'."), server.c_str());
01064 return false;
01065 }
01066
01067 if ( !ftp.ChDir(path) )
01068 {
01069 wxLogError(wxT("Couldn't change the directory to '%s'."), path.c_str());
01070 return false;
01071 }
01072
01073
01074 wxString destfile = path;
01075 if (destfile.Last() != wxT('/'))
01076 destfile += wxT('/');
01077 destfile += wxFileName(GetDownloadPath()).GetFullName();
01078
01079 wxOutputStream *out = ftp.GetOutputStream(destfile);
01080 if ( out )
01081 {
01082 wxFileInputStream source(GetDownloadPath());
01083 if (!IsOk())
01084 {
01085 wxLogError(wxT("Couldn't open the source file '%s'."), GetDownloadPath().c_str());
01086 wxDELETE(out);
01087 return false;
01088 }
01089
01090 out->Write(source);
01091
01092 if (out->GetLastError() != wxSTREAM_NO_ERROR)
01093 {
01094 wxLogError(wxT("Couldn't write to the destination file '%s'."), destfile.c_str());
01095 wxDELETE(out);
01096 return false;
01097 }
01098
01099 wxDELETE(out);
01100 }
01101
01102 ftp.Close();
01103 return true;
01104 }
01105
01106
01107 bool wxPackage::LoadGlobals(wxConfigBase *p, const wxString &path)
01108 {
01109 int num;
01110 wxString str;
01111
01112
01113 if (!p->Read(path + wxT("/LocalRepo/Num"), &num))
01114 return false;
01115 for (int i=0; i < num; i++)
01116 {
01117 if (p->Read(path + wxString::Format(wxT("/LocalRepo/Path%d"), i), &str))
01118 {
01119 if (wxFileName::IsDirWritable(str))
01120 s_arrLocalRepo.Add(str);
01121 else
01122 wxLogWarning(_("Discarded the '%s' local repository path as it's not writable."),
01123 str.c_str());
01124 }
01125 }
01126
01127
01128 if (!p->Read(path + wxT("/RemoteRepo/Num"), &num))
01129 return false;
01130 for (int i=0; i < num; i++)
01131 if (p->Read(path + wxString::Format(wxT("/RemoteRepo/Path%d"), i), &str))
01132 s_arrRemoteRepo.Add(str);
01133
01134 return s_arrLocalRepo.GetCount() > 0 &&
01135 s_arrRemoteRepo.GetCount() > 0;
01136 }
01137
01138
01139 void wxPackage::SaveGlobals(wxConfigBase *p, const wxString &path)
01140 {
01141
01142 p->DeleteGroup(path + wxT("/LocalRepo"));
01143 for (size_t i=0; i < s_arrLocalRepo.GetCount(); i++)
01144 p->Write(path + wxString::Format(wxT("/LocalRepo/Path%d"), i),
01145 s_arrLocalRepo[i]);
01146 p->Write(path + wxT("/LocalRepo/Num"), (long)s_arrLocalRepo.GetCount());
01147
01148
01149 p->DeleteGroup(path + wxT("/RemoteRepo"));
01150 for (size_t i=0; i < s_arrRemoteRepo.GetCount(); i++)
01151 p->Write(path + wxString::Format(wxT("/RemoteRepo/Path%d"), i),
01152 s_arrRemoteRepo[i]);
01153 p->Write(path + wxT("/RemoteRepo/Num"), (long)s_arrRemoteRepo.GetCount());
01154 }
01155
01156
01157
01158
01159
01160
01161
01162 bool wxPackageArray::LoadPackagesStatusInfo(wxConfigBase *cfg, const wxString &path)
01163 {
01164 size_t failedcount=0;
01165
01166
01167 for (size_t i=0; i<GetCount(); i++)
01168 {
01169 wxString id = Item(i).GetName() + wxT(" ") + Item(i).GetVersion();
01170
01171 if (cfg->HasGroup(path + wxT("/Status/") + id))
01172 {
01173 if (!Item(i).LoadStatusInfo(cfg, path + wxT("/Status/") + id))
01174 failedcount++;
01175 }
01176 }
01177
01178 return failedcount == 0;
01179 }
01180
01181 bool wxPackageArray::SavePackagesStatusInfo(wxConfigBase *cfg, const wxString &path) const
01182 {
01183 size_t failedcount=0;
01184
01185
01186 cfg->DeleteGroup(path + wxT("/Status"));
01187 for (size_t i=0; i<GetCount(); i++)
01188 {
01189 wxString id = Item(i).GetName() + wxT(" ") + Item(i).GetVersion();
01190 if (!Item(i).SaveStatusInfo(cfg, path + wxT("/Status/") + id))
01191 {
01192 failedcount++;
01193 wxLogError(wxT("Could not save status info for package '%s'."), id.c_str());
01194 }
01195 }
01196
01197 return failedcount == 0;
01198 }
01199
01200 bool wxPackageArray::LoadCompressedPackagesFrom(const wxString &path)
01201 {
01202 if (!wxFileName::DirExists(path))
01203 return false;
01204
01205 wxArrayString wxplist;
01206 size_t failedcount=0;
01207
01208 const wxString extensions[] = { wxT("*.wxz"), wxT("*.zip"), wxT("*.tar.gz") };
01209
01210 for (size_t j=0; j < WXSIZEOF(extensions); j++)
01211 {
01212 wxplist.Clear();
01213 wxDir::GetAllFiles(path, &wxplist, extensions[j], wxDIR_FILES);
01214 for (size_t i=0; i<wxplist.GetCount(); i++)
01215 {
01216 wxPackage pkg;
01217 if (!pkg.LoadCompressedPackage(wxplist[i]))
01218 {
01219 failedcount++;
01220 wxLogError(
01221 wxT("Could not load the '%s' package; it's not a valid wxWidgets package."),
01222 wxplist[i].c_str());
01223 }
01224 else
01225 {
01226 Add(pkg);
01227 }
01228 }
01229 }
01230
01231 return GetCount() > 0 ||
01232 failedcount == 0;
01233 }
01234
01235 bool wxPackageArray::LoadCompressedPackagesFromLocalRepo()
01236 {
01237 bool success = true;
01238
01239 for (size_t i=0; i<wxPackage::s_arrLocalRepo.GetCount(); i++)
01240 success &= LoadCompressedPackagesFrom(wxPackage::s_arrLocalRepo[i]);
01241
01242 return success;
01243 }
01244
01245 size_t wxPackageArray::RemoveDuplicates()
01246 {
01247 size_t removed=0;
01248
01249 for (size_t i=0; i<GetCount(); i++)
01250 {
01251 for (size_t j=i+1; j<GetCount(); j++)
01252 {
01253
01254
01255 if (Item(i).HasSameIdOf(Item(j)))
01256 {
01257 RemoveAt(j);
01258 removed++;
01259
01260
01261 j--;
01262 }
01263 }
01264 }
01265
01266 return removed;
01267 }
01268
01269 bool wxPackageArray::UpdatePackage(const wxPackage &pkg)
01270 {
01271 int n = IndexById(pkg);
01272 if (n == wxNOT_FOUND)
01273 return false;
01274
01275
01276 RemoveAt(n);
01277 Insert(pkg, n);
01278 return true;
01279 }
01280
01281 bool wxPackageArray::GetRecursiveDependencies(wxPackageDependencyArray *ret,
01282 const wxPackageArray &arr,
01283 wxPackageDependencyType type,
01284 wxPackageDependencyArray *notfound) const
01285 {
01286 bool success = true;
01287 for (size_t i=0; i<GetCount(); i++)
01288 success &= Item(i).GetRecursiveDependencies(ret, arr, type, notfound);
01289
01290 return success;
01291 }
01292
01293 wxPackageArray wxPackageArray::GetPackagesWhichBelongTo(wxPackageCategory cat) const
01294 {
01295 wxPackageArray ret;
01296 for (size_t i=0; i<GetCount(); i++)
01297 if (Item(i).GetPrimaryCategory() == cat ||
01298 Item(i).GetSecondaryCategory() == cat)
01299 ret.Add(Item(i));
01300 return ret;
01301 }
01302
01303 void wxPackageArray::InvalidateCachedSubstHashMap(wxPackageSubstituteInfoContext ctx)
01304 {
01305 for (size_t i=0; i<GetCount(); i++)
01306 Item(i).InvalidateCachedSubstHashMap(ctx);
01307 }