Ticket #14488: fswatcherfixes.diff

File fswatcherfixes.diff, 12.9 KB (added by dghart, 6 years ago)
  • include/wx/fswatcher.h

    diff --git a/include/wx/fswatcher.h b/include/wx/fswatcher.h
    index 9792bce..1d9e2eb 100644
    a b public: 
    200200    {
    201201    }
    202202
    203     wxFSWatchInfo(const wxString& path, int events, wxFSWPathType type) :
    204         m_path(path), m_events(events), m_type(type)
     203    wxFSWatchInfo(const wxString& path, int events, wxFSWPathType type, const wxString& filespec = "") :
     204        m_path(path), m_filespec(filespec), m_events(events), m_type(type)
    205205    {
    206206    }
    207207
    public: 
    210210        return m_path;
    211211    }
    212212
     213    const wxString& GetFilespec() const
     214    {
     215        return m_filespec;
     216    }
     217
    213218    int GetFlags() const
    214219    {
    215220        return m_events;
    public: 
    222227
    223228protected:
    224229    wxString m_path;
     230    wxString m_filespec;      // For tree watches, holds any filespec to apply
    225231    int m_events;
    226232    wxFSWPathType m_type;
    227233};
    public: 
    260266     * of particular type.
    261267     */
    262268    virtual bool AddTree(const wxFileName& path, int events = wxFSW_EVENT_ALL,
    263                          const wxString& filter = wxEmptyString);
     269                         const wxString& filespec = wxEmptyString);
    264270
    265271    /**
    266272     * Removes path from the list of watched paths.
    public: 
    310316    //
    311317    // Delegates the real work of adding the path to wxFSWatcherImpl::Add() and
    312318    // updates m_watches if the new path was successfully added.
    313     bool AddAny(const wxFileName& path, int events, wxFSWPathType type);
     319    bool AddAny(const wxFileName& path, int events, wxFSWPathType type,
     320                                const wxString& filespec = "");
    314321
    315322protected:
    316323
  • src/common/fswatchercmn.cpp

    diff --git a/src/common/fswatchercmn.cpp b/src/common/fswatchercmn.cpp
    index 7382c2f..c509186 100644
    a b bool wxFileSystemWatcherBase::Add(const wxFileName& path, int events) 
    101101bool
    102102wxFileSystemWatcherBase::AddAny(const wxFileName& path,
    103103                                int events,
    104                                 wxFSWPathType type)
     104                                wxFSWPathType type,
     105                                const wxString& filespec /*= ""*/)
    105106{
    106107    wxString canonical = GetCanonicalPath(path);
    107108    if (canonical.IsEmpty())
    wxFileSystemWatcherBase::AddAny(const wxFileName& path, 
    111112                wxString::Format("Path '%s' is already watched", canonical));
    112113
    113114    // adding a path in a platform specific way
    114     wxFSWatchInfo watch(canonical, events, type);
     115    wxFSWatchInfo watch(canonical, events, type, filespec);
    115116    if ( !m_service->Add(watch) )
    116117        return false;
    117118
    bool wxFileSystemWatcherBase::Remove(const wxFileName& path) 
    140141}
    141142
    142143bool wxFileSystemWatcherBase::AddTree(const wxFileName& path, int events,
    143                                       const wxString& filter)
     144                                      const wxString& filespec)
    144145{
    145146    if (!path.DirExists())
    146147        return false;
    bool wxFileSystemWatcherBase::AddTree(const wxFileName& path, int events, 
    150151    class AddTraverser : public wxDirTraverser
    151152    {
    152153    public:
    153         AddTraverser(wxFileSystemWatcherBase* watcher, int events) :
    154             m_watcher(watcher), m_events(events)
     154        AddTraverser(wxFileSystemWatcherBase* watcher, int events,
     155                    const wxString& filespec) :
     156            m_watcher(watcher), m_events(events), m_filespec(filespec)
    155157        {
    156158        }
    157159
    bool wxFileSystemWatcherBase::AddTree(const wxFileName& path, int events, 
    161163        // about that, but Add() should also behave well then
    162164        virtual wxDirTraverseResult OnFile(const wxString& filename)
    163165        {
    164             wxLogTrace(wxTRACE_FSWATCHER,
     166            if (m_watcher->AddAny(wxFileName::FileName(filename),
     167                                  m_events, wxFSWPath_File))
     168            {
     169                wxLogTrace(wxTRACE_FSWATCHER,
    165170                       "--- AddTree adding file '%s' ---", filename);
    166             m_watcher->AddAny(wxFileName::FileName(filename),
    167                              m_events, wxFSWPath_File);
     171            }
    168172            return wxDIR_CONTINUE;
    169173        }
    170174
    171175        virtual wxDirTraverseResult OnDir(const wxString& dirname)
    172176        {
    173             wxLogTrace(wxTRACE_FSWATCHER,
    174                        "--- AddTree adding directory '%s' ---", dirname);
    175177            // we add as much as possible and ignore errors
    176             m_watcher->AddAny(wxFileName::DirName(dirname),
    177                              m_events, wxFSWPath_Dir);
     178            // However if there's a filespec, only pass the dir if it matches
     179            // otherwise all its files will be watched, whatever their ext
     180            // The easiest way to get any ext is to pretend it's a file :)
     181            wxFileName fn(wxFileName::FileName(dirname));
     182            if (m_filespec.empty() ||
     183                wxMatchWild(m_filespec, "*." + fn.GetExt()))
     184            {
     185                if (m_watcher->AddAny(wxFileName::DirName(dirname),
     186                                      m_events, wxFSWPath_Dir))
     187                {
     188                    wxLogTrace(wxTRACE_FSWATCHER,
     189                       "--- AddTree adding directory '%s' ---", dirname);
     190                }
     191            }
    178192            return wxDIR_CONTINUE;
    179193        }
    180194
    181195    private:
    182196        wxFileSystemWatcherBase* m_watcher;
    183197        int m_events;
    184         wxString m_filter;
     198        wxString m_filespec;
    185199    };
    186200
    187201    wxDir dir(path.GetFullPath());
    188     AddTraverser traverser(this, events);
    189     dir.Traverse(traverser, filter);
     202    AddTraverser traverser(this, events, filespec);
     203    dir.Traverse(traverser, filespec);
    190204
    191205    // Add the path itself explicitly as Traverse() doesn't return it.
    192     Add(path.GetPathWithSep(), events);
     206    AddAny(path.GetPathWithSep(), events, wxFSWPath_Dir, filespec);
    193207
    194208    return true;
    195209}
    bool wxFileSystemWatcherBase::RemoveTree(const wxFileName& path) 
    204218    class RemoveTraverser : public wxDirTraverser
    205219    {
    206220    public:
    207         RemoveTraverser(wxFileSystemWatcherBase* watcher) :
    208             m_watcher(watcher)
     221        RemoveTraverser(wxFileSystemWatcherBase* watcher,
     222                        const wxString& filespec) :
     223            m_watcher(watcher), m_filespec(filespec)
    209224        {
    210225        }
    211226
    bool wxFileSystemWatcherBase::RemoveTree(const wxFileName& path) 
    217232
    218233        virtual wxDirTraverseResult OnDir(const wxString& dirname)
    219234        {
    220             m_watcher->Remove(wxFileName::DirName(dirname));
     235            // If there's a filespec, only matching dirs will have been watched
     236            wxFileName fn(wxFileName::FileName(dirname));
     237            if (m_filespec.empty() ||
     238                wxMatchWild(m_filespec, "*." + fn.GetExt()))
     239            {
     240                m_watcher->Remove(wxFileName::DirName(dirname));
     241            }
    221242            return wxDIR_CONTINUE;
    222243        }
    223244
    224245    private:
    225246        wxFileSystemWatcherBase* m_watcher;
     247        wxString m_filespec;
    226248    };
    227249
     250    // If AddTree() used a filespec, we must use the same one
     251    wxString canonical = GetCanonicalPath(path);
     252    wxFSWatchInfoMap::iterator it = m_watches.find(canonical);
     253    wxCHECK_MSG(it != m_watches.end(), false,
     254                wxString::Format("Path '%s' is not watched", canonical));
     255    wxFSWatchInfo watch = it->second;
     256    const wxString filespec = watch.GetFilespec();
     257
     258#if defined(__WINDOWS__)
     259    // When there's no filespec, the wxMSW AddTree() would have set a watch
     260    // on only the passed 'path'. We must therefore remove only this
     261    if (filespec.empty())
     262    {
     263        return Remove(path);
     264    }
     265    // Otherwise fall through to the generic implementation
     266#endif // __WINDOWS__
     267
    228268    wxDir dir(path.GetFullPath());
    229     RemoveTraverser traverser(this);
    230     dir.Traverse(traverser);
     269    RemoveTraverser traverser(this, filespec);
     270    dir.Traverse(traverser, filespec);
    231271
    232272    // As in AddTree() above, handle the path itself explicitly.
    233273    Remove(path);
  • tests/fswatcher/fswatchertest.cpp

    diff --git a/tests/fswatcher/fswatchertest.cpp b/tests/fswatcher/fswatchertest.cpp
    index 2f9ff84..7e226a1 100644
    a b private: 
    417417    CPPUNIT_TEST_SUITE( FileSystemWatcherTestCase );
    418418        CPPUNIT_TEST( TestEventCreate );
    419419        CPPUNIT_TEST( TestEventDelete );
    420 
    421         // FIXME: Currently this test fails under Windows.
    422 #ifndef __WINDOWS__
     420#if !defined(__VISUALC__) || wxCHECK_VISUALC_VERSION(7)
    423421        CPPUNIT_TEST( TestTrees );
    424 #endif // __WINDOWS__
     422#endif
    425423
    426424        // kqueue-based implementation doesn't collapse create/delete pairs in
    427425        // renames and doesn't detect neither modifications nor access to the
    private: 
    446444    void TestEventRename();
    447445    void TestEventModify();
    448446    void TestEventAccess();
    449 #ifndef __WINDOWS__
    450     void TestTrees();
    451 #endif // __WINDOWS__
    452 
     447#if !defined(__VISUALC__) || wxCHECK_VISUALC_VERSION(7)
     448    void TestTrees();   // Visual C++ 6 can't build this
     449#endif
    453450    void TestNoEventsAfterRemove();
    454451
    455452    DECLARE_NO_COPY_CLASS(FileSystemWatcherTestCase)
    void FileSystemWatcherTestCase::TestEventAccess() 
    641638// ----------------------------------------------------------------------------
    642639// TestTrees
    643640// ----------------------------------------------------------------------------
    644 #ifndef __WINDOWS__
     641
     642#if !defined(__VISUALC__) || wxCHECK_VISUALC_VERSION(7)
    645643void FileSystemWatcherTestCase::TestTrees()
    646644{
    647645    class TreeTester : public EventHandler
    void FileSystemWatcherTestCase::TestTrees() 
    664662                CPPUNIT_ASSERT(dir.Mkdir());
    665663
    666664                const wxString prefix = dir.GetPathWithSep();
     665                const wxString ext[] = { ".txt", ".log", "" };
    667666                for ( unsigned f = 0; f < files; ++f )
    668667                {
    669668                    // Just create the files.
    670                     wxFile(prefix + wxString::Format("file%u", f+1),
     669                    wxFile(prefix + wxString::Format("file%u", f+1) + ext[f],
    671670                           wxFile::write);
    672671                }
    673672            }
    void FileSystemWatcherTestCase::TestTrees() 
    707706        {
    708707            CPPUNIT_ASSERT(m_watcher);
    709708
    710             const size_t
    711                 treeitems = (subdirs*files) + subdirs + 1; // +1 for the trunk
     709            size_t treeitems = 1; // the trunk
     710#ifndef __WINDOWS__
     711            // When there's no file mask, wxMSW sets a single watch
     712            // on the trunk which is implemented recursively.
     713            // wxGTK always sets an additional watch for each file/subdir
     714            treeitems += (subdirs*files) + subdirs;
     715#endif // __WINDOWS__
    712716
    713717            // Store the initial count; there may already be some watches
    714718            const int initial = m_watcher->GetWatchedPathsCount();
    void FileSystemWatcherTestCase::TestTrees() 
    724728            CPPUNIT_ASSERT_EQUAL(initial, m_watcher->GetWatchedPathsCount());
    725729        }
    726730
     731        void WatchTreeWithFilespec(const wxFileName& dir)
     732        {
     733            CPPUNIT_ASSERT(m_watcher);
     734            CPPUNIT_ASSERT(dir.DirExists()); // Was built in WatchTree()
     735
     736            // Store the initial count; there may already be some watches
     737            const int initial = m_watcher->GetWatchedPathsCount();
     738
     739            // When we use a filter, both wxMSW and wxGTK implementations set
     740            // an additional watch for each file/subdir. Test by passing *.txt
     741            // We expect the dirs and the other 2 files to be skipped
     742            const size_t treeitems = subdirs + 1;
     743            m_watcher->AddTree(dir, wxFSW_EVENT_ALL, "*.txt");
     744
     745            const int plustree = m_watcher->GetWatchedPathsCount();
     746            CPPUNIT_ASSERT_EQUAL(initial + treeitems, plustree);
     747
     748            // RemoveTree should try to remove only those files that were added
     749            m_watcher->RemoveTree(dir);
     750            CPPUNIT_ASSERT_EQUAL(initial, m_watcher->GetWatchedPathsCount());
     751        }
     752
    727753        void RemoveAllWatches()
    728754        {
    729755            CPPUNIT_ASSERT(m_watcher);
    void FileSystemWatcherTestCase::TestTrees() 
    750776
    751777            WatchDir(singledir);
    752778            WatchTree(treedir);
     779            // Now test adding and removing a tree using a filespec
     780            // wxMSW uses the generic method to add matching files; which fails
     781            // as it doesn't support adding files :/ So disable the test
     782#ifndef __WINDOWS__
     783            WatchTreeWithFilespec(treedir);
     784#endif // __WINDOWS__
    753785
    754786            RemoveSingleWatch(singledir);
    755787            // Add it back again, ready to test RemoveAll()
    756788            WatchDir(singledir);
    757789
    758790            RemoveAllWatches();
    759 
     791           
    760792            // Clean up
    761793            RmDir(singledir);
    762794            RmDir(treedir);
    void FileSystemWatcherTestCase::TestTrees() 
    781813    TreeTester tester;
    782814    tester.Run();
    783815}
    784 #endif // __WINDOWS__
     816#endif // !defined(__VISUALC__) || wxCHECK_VISUALC_VERSION(7)
     817
    785818
    786819namespace
    787820{