[Jython-checkins] jython: Refactoring around os.uname() to extract common code.

jeff.allen jython-checkins at python.org
Tue Jan 1 18:58:22 EST 2019


https://hg.python.org/jython/rev/4bbacf481833
changeset:   8212:4bbacf481833
user:        Jeff Allen <ja.py at farowl.co.uk>
date:        Tue Jan 01 23:14:03 2019 +0000
summary:
  Refactoring around os.uname() to extract common code.

Use Py.getCommandResult and Py.getenv, the latter so that os.environ is
consulted to pick up changes. Also a slight tweak to the logic allows us to pass
test_uname_win32_ARCHITEW6432 in test_platform, if that test is enabled and
uname_cache disabled (temporarily).

Top-level classes hiding in Hider.java are made nested to placate IDE linters.

files:
  Lib/test/test_platform.py                     |    1 +
  src/org/python/core/PrePy.java                |   33 +
  src/org/python/core/PySystemState.java        |   34 +-
  src/org/python/modules/posix/Hider.java       |   37 +-
  src/org/python/modules/posix/PosixModule.java |  227 +++------
  5 files changed, 137 insertions(+), 195 deletions(-)


diff --git a/Lib/test/test_platform.py b/Lib/test/test_platform.py
--- a/Lib/test/test_platform.py
+++ b/Lib/test/test_platform.py
@@ -136,6 +136,7 @@
         self.assertTrue(any(res))
 
     @unittest.skipUnless(sys.platform.startswith('win'), "windows only test")
+    # One may enable this for Jython, but must disable the cache in os.uname() to pass.
     def test_uname_win32_ARCHITEW6432(self):
         # Issue 7860: make sure we get architecture from the correct variable
         # on 64 bit Windows: if PROCESSOR_ARCHITEW6432 exists we should be
diff --git a/src/org/python/core/PrePy.java b/src/org/python/core/PrePy.java
--- a/src/org/python/core/PrePy.java
+++ b/src/org/python/core/PrePy.java
@@ -264,4 +264,37 @@
         }
         return url;
     }
+
+    /**
+     * Run a command as a sub-process and return as the result the first line of output that
+     * consists of more than white space. It returns "" on any kind of error.
+     *
+     * @param command as strings (as for <code>ProcessBuilder</code>)
+     * @return the first line with content, or ""
+     */
+    public static String getCommandResult(String... command) {
+        String result = "", line = null;
+        ProcessBuilder pb = new ProcessBuilder(command);
+        try {
+            Process p = pb.start();
+            java.io.BufferedReader br =
+                    new java.io.BufferedReader(new java.io.InputStreamReader(p.getInputStream()));
+            // We read to the end-of-stream in case the sub-process cannot end cleanly without.
+            while ((line = br.readLine()) != null) {
+                if (line.length() > 0 && result.length() == 0) {
+                    // This is the first line with content (maybe).
+                    result = line.trim();
+                }
+            }
+            br.close();
+            // Now we wait for the sub-process to terminate nicely.
+            if (p.waitFor() != 0) {
+                // Bad exit status: don't take the result.
+                result = "";
+            }
+        } catch (IOException | InterruptedException | SecurityException e) {
+            result = "";
+        }
+        return result;
+    }
 }
diff --git a/src/org/python/core/PySystemState.java b/src/org/python/core/PySystemState.java
--- a/src/org/python/core/PySystemState.java
+++ b/src/org/python/core/PySystemState.java
@@ -996,7 +996,7 @@
 
         } else if (os != null && os.startsWith("Windows")) {
             // Go via the Windows code page built-in command "chcp".
-            String output = getCommandResult("cmd", "/c", "chcp");
+            String output = Py.getCommandResult("cmd", "/c", "chcp");
             /*
              * The output will be like "Active code page: 850" or maybe "Aktive Codepage: 1252." or
              * "활성 코드 페이지: 949". Assume the first number with 2 or more digits is the code page.
@@ -1009,7 +1009,7 @@
 
         } else {
             // Try a Unix-like "locale charmap".
-            String output = getCommandResult("locale", "charmap");
+            String output = Py.getCommandResult("locale", "charmap");
             // The result of "locale charmap" is just the charmap name ~ Charset or codec name.
             if (output.length() > 0) {
                 return output;
@@ -1782,10 +1782,10 @@
             // "Microsoft Windows [版本 10.0.17134.472]"
             // We match the dots and digits within square brackets.
             Pattern p = Pattern.compile("\\[.* ([\\d.]+)\\]");
-            Matcher m = p.matcher(getCommandResult("cmd.exe", "/c", "ver"));
+            Matcher m = p.matcher(Py.getCommandResult("cmd.exe", "/c", "ver"));
             return m.find() ? m.group(1) : "";
         } else {
-            return getCommandResult("uname", "-v");
+            return Py.getCommandResult("uname", "-v");
         }
     }
 
@@ -1795,31 +1795,11 @@
      *
      * @param command as strings (as for <code>ProcessBuilder</code>)
      * @return the first line with content, or ""
+     * @deprecated Use {@link Py#getCommandResult(String...)} instead
      */
+    @Deprecated
     private static String getCommandResult(String... command) {
-        String result = "", line = null;
-        ProcessBuilder pb = new ProcessBuilder(command);
-        try {
-            Process p = pb.start();
-            java.io.BufferedReader br =
-                    new java.io.BufferedReader(new java.io.InputStreamReader(p.getInputStream()));
-            // We read to the end-of-stream in case the sub-process cannot end cleanly without.
-            while ((line = br.readLine()) != null) {
-                if (line.length() > 0 && result.length() == 0) {
-                    // This is the first line with content (maybe).
-                    result = line.trim();
-                }
-            }
-            br.close();
-            // Now we wait for the sub-process to terminate nicely.
-            if (p.waitFor() != 0) {
-                // Bad exit status: don't take the result.
-                result = "";
-            }
-        } catch (IOException | InterruptedException | SecurityException e) {
-            result = "";
-        }
-        return result;
+        return PrePy.getCommandResult(command);
     }
 
     /* Traverseproc implementation */
diff --git a/src/org/python/modules/posix/Hider.java b/src/org/python/modules/posix/Hider.java
--- a/src/org/python/modules/posix/Hider.java
+++ b/src/org/python/modules/posix/Hider.java
@@ -50,27 +50,24 @@
         }
         return false;
     }
-}
 
-/**
- * Tags PosixModule methods as hidden on the specified OS or PosixImpl.
- */
- at Retention(RetentionPolicy.RUNTIME)
- at Target(ElementType.METHOD)
- at interface Hide {
+    /** Tags PosixModule methods as hidden on the specified OS or PosixImpl. */
+    @Retention(RetentionPolicy.RUNTIME)
+    @Target(ElementType.METHOD)
+    @interface Hide {
 
-    /** Hide method on these OSes. */
-    OS[] value() default {};
+        /** Hide method on these OSes. */
+        OS[] value() default {};
 
-    /**
-     * @Hide(posixImpl = PosixImpl.JAVA) hides the method from Python when the POSIX
-     * library isn't native. The default NOT_APPLICABLE means the POSIX implementation
-     * doesn't matter.
-     */
-    PosixImpl posixImpl() default PosixImpl.NOT_APPLICABLE;
+        /**
+         * @Hide(posixImpl = PosixImpl.JAVA) hides the method from Python when the POSIX
+         * library isn't native. The default NOT_APPLICABLE means the POSIX implementation
+         * doesn't matter.
+         */
+        PosixImpl posixImpl() default PosixImpl.NOT_APPLICABLE;
+    }
+
+    /** The type of underlying POSIX library implementation (native or not). */
+    enum PosixImpl {NOT_APPLICABLE, NATIVE, JAVA};
+
 }
-
-/**
- * The type of underlying POSIX library implementation (native or not).
- */
-enum PosixImpl {NOT_APPLICABLE, NATIVE, JAVA};
diff --git a/src/org/python/modules/posix/PosixModule.java b/src/org/python/modules/posix/PosixModule.java
--- a/src/org/python/modules/posix/PosixModule.java
+++ b/src/org/python/modules/posix/PosixModule.java
@@ -343,7 +343,7 @@
     public static PyString __doc__chown = new PyString(
         "chown(path, uid, gid)\n\n" +
         "Change the owner and group id of path to the numeric uid and gid.");
-    @Hide(OS.NT)
+    @Hider.Hide(OS.NT)
     public static void chown(PyObject path, int uid, int gid) {
         if (posix.chown(absolutePath(path).toString(), uid, gid) < 0) {
             throw errorFromErrno(path);
@@ -362,7 +362,7 @@
         }
     }
 
-    @Hide(OS.NT)
+    @Hider.Hide(OS.NT)
     public static void closerange(PyObject fd_lowObj, PyObject fd_highObj) {
         int fd_low = getFD(fd_lowObj).getIntFD(false);
         int fd_high = getFD(fd_highObj).getIntFD(false);
@@ -424,7 +424,7 @@
         "fdatasync(fildes)\n\n" +
         "force write of file with filedescriptor to disk.\n" +
         "does not force update of metadata.");
-    @Hide(OS.NT)
+    @Hider.Hide(OS.NT)
     public static void fdatasync(PyObject fd) {
         Object javaobj = fd.__tojava__(RawIOBase.class);
         if (javaobj != Py.NoConversion) {
@@ -501,7 +501,7 @@
     public static PyString __doc__getegid = new PyString(
         "getegid() -> egid\n\n" +
         "Return the current process's effective group id.");
-    @Hide(OS.NT)
+    @Hider.Hide(OS.NT)
     public static int getegid() {
         return posix.getegid();
     }
@@ -509,7 +509,7 @@
     public static PyString __doc__geteuid = new PyString(
         "geteuid() -> euid\n\n" +
         "Return the current process's effective user id.");
-    @Hide(OS.NT)
+    @Hider.Hide(OS.NT)
     public static int geteuid() {
         return posix.geteuid();
     }
@@ -517,7 +517,7 @@
     public static PyString __doc__getgid = new PyString(
         "getgid() -> gid\n\n" +
         "Return the current process's group id.");
-    @Hide(value=OS.NT, posixImpl = PosixImpl.JAVA)
+    @Hider.Hide(value=OS.NT, posixImpl = Hider.PosixImpl.JAVA)
     public static int getgid() {
         return posix.getgid();
     }
@@ -525,7 +525,7 @@
     public static PyString __doc__getlogin = new PyString(
         "getlogin() -> string\n\n" +
         "Return the actual login name.");
-    @Hide(value=OS.NT, posixImpl = PosixImpl.JAVA)
+    @Hider.Hide(value=OS.NT, posixImpl = Hider.PosixImpl.JAVA)
     public static PyObject getlogin() {
         String login = posix.getlogin();
         if (login == null) {
@@ -539,7 +539,7 @@
     public static PyString __doc__getppid = new PyString(
         "getppid() -> ppid\n\n" +
         "Return the parent's process id.");
-    @Hide(value=OS.NT, posixImpl = PosixImpl.JAVA)
+    @Hider.Hide(value=OS.NT, posixImpl = Hider.PosixImpl.JAVA)
     public static int getppid() {
         return posix.getppid();
     }
@@ -547,7 +547,7 @@
     public static PyString __doc__getuid = new PyString(
         "getuid() -> uid\n\n" +
         "Return the current process's user id.");
-    @Hide(value=OS.NT, posixImpl = PosixImpl.JAVA)
+    @Hider.Hide(value=OS.NT, posixImpl = Hider.PosixImpl.JAVA)
     public static int getuid() {
         return posix.getuid();
     }
@@ -556,7 +556,7 @@
         "getpid() -> pid\n\n" +
         "Return the current process id");
 
-    @Hide(posixImpl = PosixImpl.JAVA)
+    @Hider.Hide(posixImpl = Hider.PosixImpl.JAVA)
     public static int getpid() {
         return posix.getpid();
     }
@@ -564,7 +564,7 @@
     public static PyString __doc__getpgrp = new PyString(
         "getpgrp() -> pgrp\n\n" +
         "Return the current process group id.");
-    @Hide(value=OS.NT, posixImpl = PosixImpl.JAVA)
+    @Hider.Hide(value=OS.NT, posixImpl = Hider.PosixImpl.JAVA)
     public static int getpgrp() {
         return posix.getpgrp();
     }
@@ -575,7 +575,7 @@
         "isatty(fd) -> bool\n\n" +
         "Return True if the file descriptor 'fd' is an open file descriptor\n" +
         "connected to the slave end of a terminal.");
-    @Hide(posixImpl = PosixImpl.JAVA)
+    @Hider.Hide(posixImpl = Hider.PosixImpl.JAVA)
     public static boolean isatty(PyObject fdObj) {
         Object tojava = fdObj.__tojava__(IOBase.class);
         if (tojava != Py.NoConversion) {
@@ -609,7 +609,7 @@
     public static PyString __doc__kill = new PyString(
         "kill(pid, sig)\n\n" +
         "Kill a process with a signal.");
-    @Hide(value=OS.NT, posixImpl = PosixImpl.JAVA)
+    @Hider.Hide(value=OS.NT, posixImpl = Hider.PosixImpl.JAVA)
     public static void kill(int pid, int sig) {
         if (posix.kill(pid, sig) < 0) {
             throw errorFromErrno();
@@ -620,7 +620,7 @@
         "lchmod(path, mode)\n\n" +
         "Change the access permissions of a file. If path is a symlink, this\n" +
         "affects the link itself rather than the target.");
-    @Hide(value=OS.NT, posixImpl = PosixImpl.JAVA)
+    @Hider.Hide(value=OS.NT, posixImpl = Hider.PosixImpl.JAVA)
     public static void lchmod(PyObject path, int mode) {
         if (posix.lchmod(absolutePath(path).toString(), mode) < 0) {
             throw errorFromErrno(path);
@@ -631,7 +631,7 @@
         "lchown(path, uid, gid)\n\n" +
         "Change the owner and group id of path to the numeric uid and gid.\n" +
         "This function will not follow symbolic links.");
-    @Hide(value=OS.NT, posixImpl = PosixImpl.JAVA)
+    @Hider.Hide(value=OS.NT, posixImpl = Hider.PosixImpl.JAVA)
     public static void lchown(PyObject path, int uid, int gid) {
         if (posix.lchown(absolutePath(path).toString(), uid, gid) < 0) {
             throw errorFromErrno(path);
@@ -642,7 +642,7 @@
         "link(src, dst)\n\n" +
         "Create a hard link to a file.");
 
-    @Hide(OS.NT)
+    @Hider.Hide(OS.NT)
     public static void link(PyObject src, PyObject dst) {
         try {
             Files.createLink(Paths.get(asPath(dst)), Paths.get(asPath(src)));
@@ -857,7 +857,7 @@
     public static PyString __doc__readlink = new PyString(
         "readlink(path) -> path\n\n" +
         "Return a string representing the path to which the symbolic link points.");
-    @Hide(OS.NT)
+    @Hider.Hide(OS.NT)
     public static PyString readlink(PyObject path) {
         try {
             return Py.newStringOrUnicode(path, Files.readSymbolicLink(absolutePath(path)).toString());
@@ -908,7 +908,7 @@
     public static PyString __doc__setpgrp = new PyString(
         "setpgrp()\n\n" +
         "Make this process a session leader.");
-    @Hide(value=OS.NT, posixImpl = PosixImpl.JAVA)
+    @Hider.Hide(value=OS.NT, posixImpl = Hider.PosixImpl.JAVA)
     public static void setpgrp() {
         if (posix.setpgrp(0, 0) < 0) {
             throw errorFromErrno();
@@ -918,7 +918,7 @@
     public static PyString __doc__setsid = new PyString(
         "setsid()\n\n" +
         "Call the system call setsid().");
-    @Hide(value=OS.NT, posixImpl = PosixImpl.JAVA)
+    @Hider.Hide(value=OS.NT, posixImpl = Hider.PosixImpl.JAVA)
     public static void setsid() {
         if (posix.setsid() < 0) {
             throw errorFromErrno();
@@ -946,7 +946,7 @@
         "symlink(src, dst)\n\n" +
         "Create a symbolic link pointing to src named dst.");
 
-    @Hide(OS.NT)
+    @Hider.Hide(OS.NT)
     public static void symlink(PyObject src, PyObject dst) {
         try {
             Files.createSymbolicLink(Paths.get(asPath(dst)), Paths.get(asPath(src)));
@@ -967,7 +967,7 @@
         "times() -> (utime, stime, cutime, cstime, elapsed_time)\n\n" +
         "Return a tuple of floating point numbers indicating process times.");
 
-    @Hide(posixImpl = PosixImpl.JAVA)
+    @Hider.Hide(posixImpl = Hider.PosixImpl.JAVA)
     public static PyTuple times() {
         Times times = posix.times();
         long CLK_TCK = Sysconf._SC_CLK_TCK.longValue();
@@ -983,7 +983,7 @@
     public static PyString __doc__umask = new PyString(
         "umask(new_mask) -> old_mask\n\n" +
         "Set the current numeric umask and return the previous umask.");
-    @Hide(posixImpl = PosixImpl.JAVA)
+    @Hider.Hide(posixImpl = Hider.PosixImpl.JAVA)
     public static int umask(int mask) {
         return posix.umask(mask);
     }
@@ -1042,138 +1042,69 @@
      * @return PyTuple containing sysname, nodename, release, version, machine
      */
     public static PyTuple uname() {
-        if (uname_cache != null) {
-            return uname_cache;
-        }
-        String sysname = System.getProperty("os.name");
-        String sysrelease;
-        boolean win;
-        if (sysname.equals("Mac OS X")) {
-            sysname = "Darwin";
-            win = false;
-            try {
-                Process p = Runtime.getRuntime().exec("uname -r");
-                java.io.BufferedReader br = new java.io.BufferedReader(
-                        new java.io.InputStreamReader(p.getInputStream()));
-                sysrelease = br.readLine();
-                // to end the process sanely in case we deal with some
-                // implementation that emits additional new-lines:
-                while (br.readLine() != null) {
-                    ;
-                }
-                br.close();
-                if (p.waitFor() != 0) {
-                    sysrelease = "";
-                }
-            } catch (Exception e) {
-                sysrelease = "";
+        if (uname_cache == null) {
+            // First call: have to construct the result.
+            String sysname = System.getProperty("os.name");
+            String sysrelease, nodename, machine;
+            boolean win = false;
+
+            if (sysname.equals("Mac OS X")) {
+                sysname = "Darwin";
+                sysrelease = Py.getCommandResult("uname", "-r");
+            } else if (sysname.startsWith("Windows")) {
+                sysrelease = sysname.length() > 7 ? sysname.substring(8)
+                        : System.getProperty("os.version", "");
+                sysname = "Windows";
+                win = true;
+            } else {
+                sysrelease = System.getProperty("os.version", "");
             }
-        } else {
-            win = sysname.startsWith("Windows");
-            if (win) {
-                sysrelease = sysname.length() > 7 ? sysname.substring(8) :
-                        System.getProperty("os.version");
-                sysname = "Windows";
-            } else {
-                sysrelease = System.getProperty("os.version");
-            }
-        }
 
-        String uname_nodename;
-        try {
-            uname_nodename = java.net.InetAddress.getLocalHost().getHostName();
-        } catch (Exception e) {
-            // Do nothing to leverage fallback
-            uname_nodename = null;
-        }
-        if (uname_nodename == null && win) {
-            uname_nodename = System.getenv("USERDOMAIN");
-        }
-        if (uname_nodename == null) {
             try {
-                Process p = Runtime.getRuntime().exec(
-                        win ? "hostname" : "uname -n");
-                java.io.BufferedReader br = new java.io.BufferedReader(
-                        new java.io.InputStreamReader(p.getInputStream()));
-                uname_nodename = br.readLine();
-                // to end the process sanely in case we deal with some
-                // implementation that emits additional new-lines:
-                while (br.readLine() != null) {
-                    ;
-                }
-                br.close();
-                if (p.waitFor() != 0) {
-                    uname_nodename = "";
-                }
+                nodename = java.net.InetAddress.getLocalHost().getHostName();
             } catch (Exception e) {
-                uname_nodename = "";
-            }
-        }
-
-        String uname_sysver = PySystemState.getSystemVersionString();
-
-        String uname_machine;
-        try {
-            if (win) {
-                String machine = System.getenv("PROCESSOR_ARCHITECTURE");
-                if (machine.equals("x86")) {
-                    // maybe 32-bit process running on 64 bit machine
-                    machine = System.getenv("PROCESSOR_ARCHITEW6432");
-                }
-                // if machine == null it's actually a 32-bit machine
-                uname_machine = machine == null ? "x86" : machine;
-// We refrain from this normalization in order to match platform.uname behavior on Windows:
-/*              if (machine == null) {
-                    uname_machine = "i686";
-                } else if (machine.equals("AMD64") || machine.equals("EM64T")) {
-                    uname_machine = "x86_64";
-                } else if (machine.equals("IA64")) {
-                    uname_machine = "ia64";
+                // If that fails, try the shell.
+                if (win) {
+                    nodename = Py.getenv("USERDOMAIN", "");
+                    if (nodename.isEmpty()) {
+                        nodename = Py.getCommandResult("hostname");
+                    }
                 } else {
-                    uname_machine = machine.toLowerCase();
-                } */
-            } else {
-                Process p = Runtime.getRuntime().exec("uname -m");
-                java.io.BufferedReader br = new java.io.BufferedReader(
-                        new java.io.InputStreamReader(p.getInputStream()));
-                uname_machine = br.readLine();
-                // to end the process sanely in case we deal with some
-                // implementation that emits additional new-lines:
-                while (br.readLine() != null) {
-                    ;
-                }
-                br.close();
-                if (p.waitFor() != 0) {
-                    // To leverage os.arch-fallback:
-                    uname_machine = null;
+                    nodename = Py.getCommandResult("uname", "-n");
                 }
             }
-        } catch (Exception e) {
-            // To leverage os.arch-fallback:
-            uname_machine = null;
+
+            String sysver = PySystemState.getSystemVersionString();
+
+            if (win) {
+                // Check if 32-bit process on a 64 bit machine (compare platform.py)
+                machine = Py.getenv("PROCESSOR_ARCHITEW6432", "");
+                if (machine.isEmpty()) {
+                    // Otherwise, this contains the value (or we default to null)
+                    machine = Py.getenv("PROCESSOR_ARCHITECTURE", "");
+                }
+            } else {
+                machine = Py.getCommandResult("uname", "-m");
+            }
+
+            if (machine.isEmpty()) {
+                machine = System.getProperty("os.arch", "");
+                if (machine.equals("amd64")) {
+                    // 64-bit processor presents as x86_64 on Linux and AMD64 on Windows.
+                    machine = win ? "AMD64" : "x86_64";
+                } else if (machine.equals("x86")) {
+                    machine = "i686";
+                }
+            }
+
+            uname_cache = new PyTuple(new PyObject[] {
+                        Py.fileSystemEncode(sysname),
+                        Py.fileSystemEncode(nodename),
+                        Py.fileSystemEncode(sysrelease),
+                        Py.fileSystemEncode(sysver),
+                        Py.fileSystemEncode(machine)},
+                false);
         }
-        if (uname_machine == null) {
-            String machine = System.getProperty("os.arch");
-            if (machine == null) {
-                uname_machine = "";
-            } else if (machine.equals("amd64")) {
-                // Normalize the common amd64-case to x86_64:
-                uname_machine = "x86_64";
-            } else if (machine.equals("x86")) {
-                uname_machine = "i686";
-            } else {
-                uname_machine = machine;
-            }
-        }
-
-        PyObject[] vals = {
-                Py.fileSystemEncode(sysname),
-                Py.fileSystemEncode(uname_nodename),
-                Py.fileSystemEncode(sysrelease),
-                Py.fileSystemEncode(uname_sysver),
-                Py.fileSystemEncode(uname_machine)
-        };
-        uname_cache = new PyTuple(vals, false);
         return uname_cache;
     }
 
@@ -1251,7 +1182,7 @@
     public static PyString __doc__wait = new PyString(
         "wait() -> (pid, status)\n\n" +
         "Wait for completion of a child process.");
-    @Hide(value=OS.NT, posixImpl = PosixImpl.JAVA)
+    @Hider.Hide(value=OS.NT, posixImpl = Hider.PosixImpl.JAVA)
     public static PyObject wait$() {
         int[] status = new int[1];
         int pid = posix.wait(status);
@@ -1264,7 +1195,7 @@
     public static PyString __doc__waitpid = new PyString(
         "wait() -> (pid, status)\n\n" +
         "Wait for completion of a child process.");
-    @Hide(posixImpl = PosixImpl.JAVA)
+    @Hider.Hide(posixImpl = Hider.PosixImpl.JAVA)
     public static PyObject waitpid(int pid, int options) {
         int[] status = new int[1];
         pid = posix.waitpid(pid, status, options);

-- 
Repository URL: https://hg.python.org/jython


More information about the Jython-checkins mailing list