GitHub PullRequestReviewCommentEvent at 2014-04-09 11:41:33
Repository: kite
Actor: tomwhite
Payload: {"comment":{"url":"https://api.github.com/repos/kite-sdk/kite/pulls/comments/11431639","id":11431639,"diff_hunk":"@@ -0,0 +1,170 @@\n+/*\n+ * Copyright 2013 Cloudera Inc.\n+ *\n+ * Licensed under the Apache License, Version 2.0 (the \"License\");\n+ * you may not use this file except in compliance with the License.\n+ * You may obtain a copy of the License at\n+ *\n+ *   http://www.apache.org/licenses/LICENSE-2.0\n+ *\n+ * Unless required by applicable law or agreed to in writing, software\n+ * distributed under the License is distributed on an \"AS IS\" BASIS,\n+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n+ * See the License for the specific language governing permissions and\n+ * limitations under the License.\n+ */\n+\n+package org.kitesdk.cli.commands;\n+\n+import com.beust.jcommander.Parameter;\n+import com.beust.jcommander.Parameters;\n+import com.beust.jcommander.internal.Lists;\n+import com.google.common.base.Preconditions;\n+import java.io.File;\n+import java.io.IOException;\n+import java.net.URL;\n+import java.net.URLClassLoader;\n+import java.nio.charset.Charset;\n+import java.security.AccessController;\n+import java.security.PrivilegedAction;\n+import java.util.List;\n+import org.apache.avro.reflect.ReflectData;\n+import org.apache.hadoop.conf.Configurable;\n+import org.apache.hadoop.conf.Configuration;\n+import org.apache.hadoop.fs.FSDataOutputStream;\n+import org.apache.hadoop.fs.FileSystem;\n+import org.apache.hadoop.fs.Path;\n+import org.kitesdk.cli.Command;\n+import org.slf4j.Logger;\n+\n+@Parameters(commandDescription = \"Build a schema from a java class\")\n+public class ObjectSchemaCommand implements Configurable, Command {\n+\n+  private static final Charset SCHEMA_CHARSET = Charset.forName(\"utf8\");\n+  private final Logger console;\n+  private Configuration conf;\n+\n+  public ObjectSchemaCommand(Logger console) {\n+    this.console = console;\n+  }\n+\n+  @Parameter(description=\"<class name>\")\n+  List<String> classNames;\n+\n+  @edu.umd.cs.findbugs.annotations.SuppressWarnings(\n+      value=\"UWF_NULL_FIELD\",\n+      justification = \"Field set by JCommander\")\n+  @Parameter(names={\"-o\", \"--output\"}, description=\"Save schema avsc to path\")\n+  String outputPath = null;\n+\n+  @Parameter(names=\"--minimize\", description=\"Minimize schema file size\")\n+  boolean minimize=false;\n+\n+  @Parameter(names=\"--jar\",\n+      description=\"Add a jar to the classpath used when loading the java class\")\n+  List<String> jars;\n+\n+  @Parameter(names=\"--lib-dir\",\n+      description=\"Add a directory to the classpath used when loading the java class\")\n+  List<String> libs;\n+\n+  @Override\n+  public int run() throws IOException {\n+    Preconditions.checkArgument(classNames != null && !classNames.isEmpty(),\n+        \"Java class name is required\");\n+    Preconditions.checkArgument(classNames.size() == 1,\n+        \"Only one java class name can be given\");\n+\n+    // check the additional jars and lib directories in the local FS\n+    final List<URL> urls = Lists.newArrayList();\n+    if (libs != null) {\n+      for (String lib : libs) {\n+        // final URLs must end in '/' for URLClassLoader\n+        File path = lib.endsWith(\"/\") ? new File(lib) : new File(lib + \"/\");\n+        Preconditions.checkArgument(path.exists(),\n+            \"Lib directory does not exist: \" + lib);\n+        Preconditions.checkArgument(path.isDirectory(),\n+            \"Not a directory: \" + lib);\n+        Preconditions.checkArgument(path.canRead() && path.canExecute(),\n+            \"Insufficient permissions to access lib directory: \" + lib);\n+        urls.add(path.toURI().toURL());\n+      }\n+    }\n+    if (jars != null) {\n+      for (String jar : jars) {\n+        File path = new File(jar);\n+        Preconditions.checkArgument(path.exists(),\n+            \"Jar files does not exist: \" + jar);\n+        Preconditions.checkArgument(path.isFile(),\n+            \"Not a file: \" + jar);\n+        Preconditions.checkArgument(path.canRead(),\n+            \"Cannot read jar file: \" + jar);\n+        urls.add(path.toURI().toURL());\n+      }\n+    }\n+\n+    ClassLoader loader = AccessController.doPrivileged(\n+        new GetClassLoader(urls));\n+\n+    String className = classNames.get(0);\n+    Class<?> recordClass;\n+    try {\n+      recordClass = loader.loadClass(className);\n+    } catch (ClassNotFoundException e) {\n+      throw new IllegalArgumentException(\"Cannot find class: \" + className, e);\n+    }\n+\n+    String schema = ReflectData.get().getSchema(recordClass).toString(!minimize);\n+\n+    if (outputPath == null || \"-\".equals(outputPath)) {\n+      console.info(schema);\n+    } else {\n+      Path out = new Path(outputPath);\n+      FileSystem outFS = out.getFileSystem(conf);\n+      FSDataOutputStream outgoing = outFS.create(out, true /* overwrite */ );\n+      try {\n+        outgoing.write(schema.getBytes(SCHEMA_CHARSET));\n+      } finally {\n+        outgoing.close();\n+      }\n+    }\n+\n+    return 0;\n+  }\n+\n+  @Override\n+  public void setConf(Configuration conf) {\n+    this.conf = conf;\n+  }\n+\n+  @Override\n+  public Configuration getConf() {\n+    return conf;\n+  }\n+\n+  @Override\n+  public List<String> getExamples() {\n+    return Lists.newArrayList(\n+        \"# Create a schema for Kite's Format class:\",","path":"kite-tools/src/main/java/org/kitesdk/cli/commands/ObjectSchemaCommand.java","position":148,"original_position":148,"commit_id":"9692303990d9e179b2eea30b8098057b60fe57b8","original_commit_id":"9692303990d9e179b2eea30b8098057b60fe57b8","user":{"login":"tomwhite","id":85085,"avatar_url":"https://avatars.githubusercontent.com/u/85085?","gravatar_id":"6304ed357cb664724690be4d04ab5603","url":"https://api.github.com/users/tomwhite","html_url":"https://github.com/tomwhite","followers_url":"https://api.github.com/users/tomwhite/followers","following_url":"https://api.github.com/users/tomwhite/following{/other_user}","gists_url":"https://api.github.com/users/tomwhite/gists{/gist_id}","starred_url":"https://api.github.com/users/tomwhite/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/tomwhite/subscriptions","organizations_url":"https://api.github.com/users/tomwhite/orgs","repos_url":"https://api.github.com/users/tomwhite/repos","events_url":"https://api.github.com/users/tomwhite/events{/privacy}","received_events_url":"https://api.github.com/users/tomwhite/received_events","type":"User","site_admin":false},"body":"This struck me as odd - why would you want to create a schema for Kite's Format class? Could we have a simple class in the CLI package to use as an example?","created_at":"2014-04-09T11:41:33Z","updated_at":"2014-04-09T11:41:33Z","html_url":"https://github.com/kite-sdk/kite/pull/56#discussion_r11431639","pull_request_url":"https://api.github.com/repos/kite-sdk/kite/pulls/56","_links":{"self":{"href":"https://api.github.com/repos/kite-sdk/kite/pulls/comments/11431639"},"html":{"href":"https://github.com/kite-sdk/kite/pull/56#discussion_r11431639"},"pull_request":{"href":"https://api.github.com/repos/kite-sdk/kite/pulls/56"}}}}