This is an automated email from the ASF dual-hosted git repository.

skygo pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/netbeans.git


The following commit(s) were added to refs/heads/master by this push:
     new 314bcd9  [NETBEANS-3745] Clean up abandoned user dirs
     new 7106cd4  Merge pull request #1897 from lkishalmi/janitor
314bcd9 is described below

commit 314bcd9d0ef67d457526dfcd5b97e868be928551
Author: Laszlo Kishalmi <[email protected]>
AuthorDate: Thu Jan 23 18:20:16 2020 -0800

    [NETBEANS-3745] Clean up abandoned user dirs
---
 nbbuild/cluster.properties                         |   1 +
 platform/core.kit/nbproject/project.xml            |   6 +
 platform/janitor/build.xml                         |  24 +++
 platform/janitor/licenseinfo.xml                   |  28 +++
 platform/janitor/manifest.mf                       |   5 +
 platform/janitor/nbproject/project.properties      |  19 ++
 platform/janitor/nbproject/project.xml             | 106 +++++++++
 .../org/netbeans/modules/janitor/Bundle.properties |  19 ++
 .../src/org/netbeans/modules/janitor/Janitor.java  | 236 +++++++++++++++++++++
 .../netbeans/modules/janitor/resources/clean.gif   | Bin 0 -> 852 bytes
 10 files changed, 444 insertions(+)

diff --git a/nbbuild/cluster.properties b/nbbuild/cluster.properties
index b19b2cf..48b940b 100644
--- a/nbbuild/cluster.properties
+++ b/nbbuild/cluster.properties
@@ -218,6 +218,7 @@ nb.cluster.platform=\
         editor.mimelookup,\
         editor.mimelookup.impl,\
         favorites,\
+        janitor,\
         javahelp,\
         junitlib,\
         keyring,\
diff --git a/platform/core.kit/nbproject/project.xml 
b/platform/core.kit/nbproject/project.xml
index 367a975..8893caa 100644
--- a/platform/core.kit/nbproject/project.xml
+++ b/platform/core.kit/nbproject/project.xml
@@ -78,6 +78,12 @@
                     </run-dependency>
                 </dependency>
                 <dependency>
+                    
<code-name-base>org.netbeans.modules.janitor</code-name-base>
+                    <run-dependency>
+                        <specification-version>1.0</specification-version>
+                    </run-dependency>
+                </dependency>
+                <dependency>
                     
<code-name-base>org.netbeans.modules.masterfs</code-name-base>
                     <run-dependency>
                         <release-version>2</release-version>
diff --git a/platform/janitor/build.xml b/platform/janitor/build.xml
new file mode 100644
index 0000000..e084b7e
--- /dev/null
+++ b/platform/janitor/build.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+    Licensed to the Apache Software Foundation (ASF) under one
+    or more contributor license agreements.  See the NOTICE file
+    distributed with this work for additional information
+    regarding copyright ownership.  The ASF licenses this file
+    to you under the Apache License, Version 2.0 (the
+    "License"); you may not use this file except in compliance
+    with the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing,
+    software distributed under the License is distributed on an
+    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+    KIND, either express or implied.  See the License for the
+    specific language governing permissions and limitations
+    under the License.
+
+-->
+<project basedir="." default="build" name="platform/janitor">
+    <import file="../../nbbuild/templates/projectized.xml"/>
+</project>
diff --git a/platform/janitor/licenseinfo.xml b/platform/janitor/licenseinfo.xml
new file mode 100644
index 0000000..7d97822
--- /dev/null
+++ b/platform/janitor/licenseinfo.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+    Licensed to the Apache Software Foundation (ASF) under one
+    or more contributor license agreements.  See the NOTICE file
+    distributed with this work for additional information
+    regarding copyright ownership.  The ASF licenses this file
+    to you under the Apache License, Version 2.0 (the
+    "License"); you may not use this file except in compliance
+    with the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing,
+    software distributed under the License is distributed on an
+    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+    KIND, either express or implied.  See the License for the
+    specific language governing permissions and limitations
+    under the License.
+
+-->
+<licenseinfo>
+    <fileset>
+        <file>src/org/netbeans/modules/janitor/resources/clean.gif</file>
+        <license ref="Apache-2.0-ASF" />
+        <comment type="COMMENT_UNSUPPORTED" />
+    </fileset>
+</licenseinfo>
diff --git a/platform/janitor/manifest.mf b/platform/janitor/manifest.mf
new file mode 100644
index 0000000..2124b90
--- /dev/null
+++ b/platform/janitor/manifest.mf
@@ -0,0 +1,5 @@
+Manifest-Version: 1.0
+OpenIDE-Module: org.netbeans.modules.janitor
+OpenIDE-Module-Localizing-Bundle: 
org/netbeans/modules/janitor/Bundle.properties
+OpenIDE-Module-Specification-Version: 1.0
+
diff --git a/platform/janitor/nbproject/project.properties 
b/platform/janitor/nbproject/project.properties
new file mode 100644
index 0000000..0f73a11
--- /dev/null
+++ b/platform/janitor/nbproject/project.properties
@@ -0,0 +1,19 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+is.autoload=true
+javac.source=1.8
+javac.compilerargs=-Xlint -Xlint:-serial
diff --git a/platform/janitor/nbproject/project.xml 
b/platform/janitor/nbproject/project.xml
new file mode 100644
index 0000000..d48778a
--- /dev/null
+++ b/platform/janitor/nbproject/project.xml
@@ -0,0 +1,106 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+    Licensed to the Apache Software Foundation (ASF) under one
+    or more contributor license agreements.  See the NOTICE file
+    distributed with this work for additional information
+    regarding copyright ownership.  The ASF licenses this file
+    to you under the Apache License, Version 2.0 (the
+    "License"); you may not use this file except in compliance
+    with the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing,
+    software distributed under the License is distributed on an
+    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+    KIND, either express or implied.  See the License for the
+    specific language governing permissions and limitations
+    under the License.
+
+-->
+<project xmlns="http://www.netbeans.org/ns/project/1";>
+    <type>org.netbeans.modules.apisupport.project</type>
+    <configuration>
+        <data xmlns="http://www.netbeans.org/ns/nb-module-project/3";>
+            <code-name-base>org.netbeans.modules.janitor</code-name-base>
+            <module-dependencies>
+                <dependency>
+                    
<code-name-base>org.netbeans.api.annotations.common</code-name-base>
+                    <build-prerequisite/>
+                    <compile-dependency/>
+                    <run-dependency>
+                        <release-version>1</release-version>
+                        <specification-version>1.34</specification-version>
+                    </run-dependency>
+                </dependency>
+                <dependency>
+                    <code-name-base>org.netbeans.api.progress</code-name-base>
+                    <build-prerequisite/>
+                    <compile-dependency/>
+                    <run-dependency>
+                        <release-version>1</release-version>
+                        <specification-version>1.54</specification-version>
+                    </run-dependency>
+                </dependency>
+                <dependency>
+                    <code-name-base>org.openide.awt</code-name-base>
+                    <build-prerequisite/>
+                    <compile-dependency/>
+                    <run-dependency>
+                        <specification-version>7.75</specification-version>
+                    </run-dependency>
+                </dependency>
+                <dependency>
+                    <code-name-base>org.openide.dialogs</code-name-base>
+                    <build-prerequisite/>
+                    <compile-dependency/>
+                    <run-dependency>
+                        <specification-version>7.49</specification-version>
+                    </run-dependency>
+                </dependency>
+                <dependency>
+                    <code-name-base>org.openide.filesystems</code-name-base>
+                    <build-prerequisite/>
+                    <compile-dependency/>
+                    <run-dependency>
+                        <specification-version>9.17</specification-version>
+                    </run-dependency>
+                </dependency>
+                <dependency>
+                    <code-name-base>org.openide.modules</code-name-base>
+                    <build-prerequisite/>
+                    <compile-dependency/>
+                    <run-dependency>
+                        <specification-version>7.55</specification-version>
+                    </run-dependency>
+                </dependency>
+                <dependency>
+                    <code-name-base>org.openide.util</code-name-base>
+                    <build-prerequisite/>
+                    <compile-dependency/>
+                    <run-dependency>
+                        <specification-version>9.14</specification-version>
+                    </run-dependency>
+                </dependency>
+                <dependency>
+                    <code-name-base>org.openide.util.ui</code-name-base>
+                    <build-prerequisite/>
+                    <compile-dependency/>
+                    <run-dependency>
+                        <specification-version>9.15</specification-version>
+                    </run-dependency>
+                </dependency>
+                <dependency>
+                    <code-name-base>org.openide.windows</code-name-base>
+                    <build-prerequisite/>
+                    <compile-dependency/>
+                    <run-dependency>
+                        <specification-version>6.84</specification-version>
+                    </run-dependency>
+                </dependency>
+            </module-dependencies>
+            <public-packages/>
+        </data>
+    </configuration>
+</project>
diff --git 
a/platform/janitor/src/org/netbeans/modules/janitor/Bundle.properties 
b/platform/janitor/src/org/netbeans/modules/janitor/Bundle.properties
new file mode 100644
index 0000000..ae1c450
--- /dev/null
+++ b/platform/janitor/src/org/netbeans/modules/janitor/Bundle.properties
@@ -0,0 +1,19 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+OpenIDE-Module-Name=Janitor
+
+OpenIDE-Module-Short-Description=Removes unused cache/data
diff --git a/platform/janitor/src/org/netbeans/modules/janitor/Janitor.java 
b/platform/janitor/src/org/netbeans/modules/janitor/Janitor.java
new file mode 100644
index 0000000..203acaa
--- /dev/null
+++ b/platform/janitor/src/org/netbeans/modules/janitor/Janitor.java
@@ -0,0 +1,236 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.netbeans.modules.janitor;
+
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.FileVisitResult;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.SimpleFileVisitor;
+import java.nio.file.attribute.BasicFileAttributes;
+import java.time.Duration;
+import java.time.Instant;
+import java.time.temporal.ChronoUnit;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.WeakHashMap;
+import java.util.concurrent.atomic.AtomicLong;
+import javax.swing.Icon;
+import org.netbeans.api.annotations.common.StaticResource;
+import org.netbeans.api.progress.ProgressHandle;
+import org.openide.*;
+import org.openide.awt.Notification;
+import org.openide.awt.NotificationDisplayer;
+import org.openide.modules.Places;
+import org.openide.util.*;
+import org.openide.util.NbBundle.Messages;
+import org.openide.windows.OnShowing;
+
+/**
+ *
+ * @author Laszlo Kishalmi
+ */
+@Messages({
+    "# {0} - is the user directory name",
+    "# {1} - the days of abandonement",
+    "# {2} - the disk space can be reclaimed (in megabytes)",
+    "TIT_ABANDONED_USERDIR=NetBeans {0} was abandoned {1} days ago.",
+    "# {0} - is the user directory name",
+    "# {1} - the days of abandonement",
+    "# {2} - the disk space can be reclaimed (in megabytes)",
+    "DESC_ABANDONED_USERDIR=Remove unused data and cache directories of 
NetBeans {0}. "
+            + "Free up {2}Mb of disk space.",
+})
+public class Janitor {
+
+    private static final long UNUSED_DAYS = 30;
+
+    private static final String LOGFILE_NAME = "var/log/messages.log"; //NOI18N
+    @StaticResource
+    private static final String CLEAN_ICON = 
"org/netbeans/modules/janitor/resources/clean.gif"; //NOI18N
+
+    static final RequestProcessor JANITOR_RP = new RequestProcessor("janitor", 
1); //NOI18N
+    static final Map<ActionListener, Notification> CLEANUP_TASKS = new 
WeakHashMap<>();
+    static final Runnable SCAN_FOR_JUNK = () -> {
+        Icon clean = ImageUtilities.loadImageIcon(CLEAN_ICON, false);
+        List<Pair<String, Integer>> otherVersions = getOtherVersions();
+
+        for (Pair<String, Integer> ver : otherVersions) {
+            long toFree = size(getUserDir(ver.first())) + 
size(getCacheDir(ver.first()));
+            toFree = toFree / (1024 * 1024) + 1;
+            ActionListener cleanupListener = cleanupAction(ver.first());
+            Notification nf = NotificationDisplayer.getDefault().notify(
+                    Bundle.TIT_ABANDONED_USERDIR(ver.first(), ver.second(), 
toFree),
+                    clean,
+                    Bundle.DESC_ABANDONED_USERDIR(ver.first(), ver.second(), 
toFree),
+                    cleanupListener);
+            CLEANUP_TASKS.put(cleanupListener, nf);
+        }
+    };
+
+    @Messages({
+        "TIT_CONFIRM_CLEANUP=Confirm Cleanup",
+        "# {0} - the dirname to be cleaned up",
+        "TXT_CONFIRM_CLEANUP=Are you sure to remove user and cache data for 
NetBeans {0}?",
+        "# {0} - the dirname to be cleaned up",
+        "LBL_CLEANUP=Removing user and cache dirs of {0}"
+    })
+    static ActionListener cleanupAction(String name) {
+        return new ActionListener() {
+            @Override
+            public void actionPerformed(ActionEvent evt) {
+                DialogDescriptor descriptor = new DialogDescriptor(
+                        Bundle.TXT_CONFIRM_CLEANUP(name),
+                        Bundle.TIT_CONFIRM_CLEANUP(),
+                        true,
+                        DialogDescriptor.YES_NO_OPTION,
+                        DialogDescriptor.YES_OPTION,
+                        null
+                );  if (DialogDescriptor.YES_OPTION == 
DialogDisplayer.getDefault().notify(descriptor)) {
+                    JANITOR_RP.post(() -> {
+                        try (ProgressHandle handle = 
ProgressHandle.createHandle(Bundle.LBL_CLEANUP(name))){
+                            handle.start();
+                            deleteDir(getUserDir(name));
+                            deleteDir(getCacheDir(name));
+                        }
+                    });
+                }
+                Notification nf = CLEANUP_TASKS.get(this);
+                if (nf != null) {
+                    nf.clear();
+                }
+            }
+        };
+    }
+
+    @OnShowing
+    public static final class PlatformOpenHook implements Runnable {
+
+        @Override
+        public void run() {
+            // Starting delayed, not to interfere with other startup IO 
operations
+            JANITOR_RP.post(SCAN_FOR_JUNK, 60_000);
+        }
+
+    }
+
+    static File getUserDir(String version) {
+        File ret = null;
+        File userDir = Places.getUserDirectory();
+        if (userDir != null) {
+            ret = new File(userDir.getParentFile(), version);
+            ret = ret.isDirectory() ? ret : null;
+        }
+
+        return ret;
+    }
+
+    static File getCacheDir(String version) {
+        File ret = null;
+        File cacheDir = Places.getCacheDirectory();
+        if (cacheDir != null) {
+            ret = new File(cacheDir.getParentFile(), version);
+            ret = ret.isDirectory() ? ret : null;
+        }
+        return ret;
+    }
+
+    static void deleteDir(File dir) {
+        if (dir == null) return;
+        Path path = dir.toPath();
+        try {
+            Files.walkFileTree(path, new SimpleFileVisitor<Path>() {
+                @Override
+                public FileVisitResult visitFile(Path file, 
BasicFileAttributes attrs) throws IOException {
+                    Files.delete(file);
+                    return FileVisitResult.CONTINUE;
+                }
+
+                @Override
+                public FileVisitResult postVisitDirectory(Path dir, 
IOException exc) throws IOException {
+                    Files.delete(dir);
+                    return FileVisitResult.CONTINUE;
+                }
+            });
+        } catch(IOException ex) {
+            // Well we've tried
+        }
+    }
+
+    public static long size(File f) {
+
+        if (f == null) {
+            return 0;
+        }
+        final Path path = f.toPath();
+        final AtomicLong size = new AtomicLong(0);
+
+        try {
+            Files.walkFileTree(path, new SimpleFileVisitor<Path>() {
+                @Override
+                public FileVisitResult visitFile(Path file, 
BasicFileAttributes attrs) {
+                    size.addAndGet(attrs.size());
+                    return FileVisitResult.CONTINUE;
+                }
+
+                @Override
+                public FileVisitResult visitFileFailed(Path file, IOException 
exc) {
+                    return FileVisitResult.CONTINUE;
+                }
+
+                @Override
+                public FileVisitResult postVisitDirectory(Path dir, 
IOException exc) {
+                    return FileVisitResult.CONTINUE;
+                }
+            });
+        } catch (IOException e) {
+        }
+
+        return size.get();
+    }
+
+    static List<Pair<String, Integer>> getOtherVersions() {
+        File userDir = Places.getUserDirectory();
+        List<Pair<String, Integer>> ret = new LinkedList<>();
+        Instant now = Instant.now();
+        if (userDir != null) {
+            File userParent = userDir.getParentFile();
+            for (File f : userParent.listFiles()) {
+                Path logFile = new File(f, LOGFILE_NAME).toPath();
+                if (!f.equals(userDir) && Files.isRegularFile(logFile)) {
+                    try {
+                        Instant lastModified = 
Files.getLastModifiedTime(logFile).toInstant();
+                        Integer age = (int) Duration.between(lastModified, 
now).toDays();
+                        if (lastModified.plus(UNUSED_DAYS, 
ChronoUnit.DAYS).isBefore(now)) {
+                                ret.add(Pair.of(f.getName(), age));
+                        }
+                    } catch (IOException ex) {
+                        //Just ignore what we can't process
+                    }
+                }
+            }
+        }
+        return ret;
+    }
+
+}
diff --git 
a/platform/janitor/src/org/netbeans/modules/janitor/resources/clean.gif 
b/platform/janitor/src/org/netbeans/modules/janitor/resources/clean.gif
new file mode 100644
index 0000000..570a323
Binary files /dev/null and 
b/platform/janitor/src/org/netbeans/modules/janitor/resources/clean.gif differ


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

For further information about the NetBeans mailing lists, visit:
https://cwiki.apache.org/confluence/display/NETBEANS/Mailing+lists

Reply via email to