Romain Rigaux 13 жил өмнө
parent
commit
f78394f
37 өөрчлөгдсөн 1624 нэмэгдсэн , 12 устгасан
  1. 4 2
      apps/Makefile
  2. 10 5
      apps/jobbrowser/src/jobbrowser/views.py
  3. 0 1
      apps/oozie/src/oozie/models.py
  4. 3 4
      apps/oozie/src/oozie/views/editor.py
  5. 24 0
      apps/pig/Makefile
  6. 2 0
      apps/pig/babel.cfg
  7. 20 0
      apps/pig/hueversion.py
  8. 29 0
      apps/pig/setup.py
  9. 15 0
      apps/pig/src/pig/__init__.py
  10. 84 0
      apps/pig/src/pig/api.py
  11. 40 0
      apps/pig/src/pig/conf.py
  12. 20 0
      apps/pig/src/pig/forms.py
  13. 35 0
      apps/pig/src/pig/locale/de/LC_MESSAGES/django.po
  14. 35 0
      apps/pig/src/pig/locale/en_US.pot
  15. 35 0
      apps/pig/src/pig/locale/en_US.pot~
  16. 35 0
      apps/pig/src/pig/locale/es/LC_MESSAGES/django.po
  17. 35 0
      apps/pig/src/pig/locale/fr/LC_MESSAGES/django.po
  18. 35 0
      apps/pig/src/pig/locale/ja/LC_MESSAGES/django.po
  19. 35 0
      apps/pig/src/pig/locale/ko/LC_MESSAGES/django.po
  20. 35 0
      apps/pig/src/pig/locale/pt/LC_MESSAGES/django.po
  21. 35 0
      apps/pig/src/pig/locale/pt_BR/LC_MESSAGES/django.po
  22. 35 0
      apps/pig/src/pig/locale/zh_CN/LC_MESSAGES/django.po
  23. 89 0
      apps/pig/src/pig/models.py
  24. 22 0
      apps/pig/src/pig/settings.py
  25. 48 0
      apps/pig/src/pig/templates/dashboard.mako
  26. 190 0
      apps/pig/src/pig/templates/editor.mako
  27. 33 0
      apps/pig/src/pig/templates/navigation-bar.inc.mako
  28. 50 0
      apps/pig/src/pig/templates/scripts.mako
  29. 46 0
      apps/pig/src/pig/templates/udfs.mako
  30. 24 0
      apps/pig/src/pig/templates/utils.inc.mako
  31. 16 0
      apps/pig/src/pig/tests.py
  32. 33 0
      apps/pig/src/pig/urls.py
  33. 158 0
      apps/pig/src/pig/views.py
  34. BIN
      apps/pig/static/art/icon_pig_24.ico
  35. 117 0
      apps/pig/static/css/pig.css
  36. 3 0
      apps/pig/static/help/index.html
  37. 194 0
      apps/pig/static/js/pig.ko.js

+ 4 - 2
apps/Makefile

@@ -41,7 +41,8 @@ APPS := about \
   proxy \
   shell \
   useradmin \
-  impala
+  impala \
+  pig
 
 ################################################
 # Install all applications into the Desktop environment
@@ -111,7 +112,8 @@ I18N_APPS := about \
   shell \
   useradmin \
   oozie \
-  impala
+  impala \
+  pig
 
 COMPILE_LOCALE_TARGETS := $(I18N_APPS:%=.recursive-compile-locales/%)
 compile-locales: $(COMPILE_LOCALE_TARGETS)

+ 10 - 5
apps/jobbrowser/src/jobbrowser/views.py

@@ -260,8 +260,8 @@ def single_task_attempt(request, job, taskid, attemptid):
 
   return render("attempt.mako", request,
     {
-      "attempt":attempt,
-      "taskid":taskid,
+      "attempt": attempt,
+      "taskid": taskid,
       "joblnk": job_link,
       "task": task
     })
@@ -297,15 +297,20 @@ def single_task_attempt_logs(request, job, taskid, attemptid):
     # Four entries,
     # for diagnostic, stdout, stderr and syslog
     logs = [ _("Failed to retrieve log. TaskTracker not found.") ] * 4
-
-  return render("attempt_logs.mako", request, {
+  
+  context = {
       "attempt": attempt,
       "taskid": taskid,
       "joblnk": job_link,
       "task": task,
       "logs": logs,
       "first_log_tab": first_log_tab,
-    })
+  }
+  
+  if request.GET.get('format') == 'python':
+    return context
+  else:
+    return render("attempt_logs.mako", request, context)
 
 @check_job_permission
 def task_attempt_counters(request, job, taskid, attemptid):

+ 0 - 1
apps/oozie/src/oozie/models.py

@@ -557,7 +557,6 @@ class Node(models.Model):
   # Can't use through relation directly with this Django version?
   # https://docs.djangoproject.com/en/1.2/topics/db/models/#intermediary-manytomany
   def get_link(self, name=None):
-    a = Link.objects.filter(parent=self)
     if name is None:
       return Link.objects.exclude(name__in=Link.META_LINKS).get(parent=self)
     else:

+ 3 - 4
apps/oozie/src/oozie/views/editor.py

@@ -239,7 +239,7 @@ def submit_workflow(request, workflow):
     if params_form.is_valid():
       mapping = dict([(param['name'], param['value']) for param in params_form.cleaned_data])
 
-      job_id = _submit_workflow(request, workflow, mapping)
+      job_id = _submit_workflow(request.user, request.fs, workflow, mapping)
 
       request.info(_('Workflow submitted'))
       return redirect(reverse('oozie:list_oozie_workflow', kwargs={'job_id': job_id}))
@@ -257,9 +257,9 @@ def submit_workflow(request, workflow):
   return HttpResponse(json.dumps(popup), mimetype="application/json")
 
 
-def _submit_workflow(request, workflow, mapping):
+def _submit_workflow(user, fs, workflow, mapping):
   try:
-    submission = Submission(request.user, workflow, request.fs, mapping)
+    submission = Submission(user, workflow, fs, mapping)
     job_id = submission.run()
     History.objects.create_from_submission(submission)
     return job_id
@@ -269,7 +269,6 @@ def _submit_workflow(request, workflow, mapping):
       detail = '%s: %s' % (_('The Oozie server is not running'), detail)
     raise PopupException(_("Error submitting workflow %s") % (workflow,), detail=detail)
 
-  request.info(_('Workflow submitted'))
   return redirect(reverse('oozie:list_oozie_workflow', kwargs={'job_id': job_id}))
 
 

+ 24 - 0
apps/pig/Makefile

@@ -0,0 +1,24 @@
+#
+# Licensed to Cloudera, Inc. under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  Cloudera, Inc. 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.
+#
+
+ifeq ($(ROOT),)
+  $(error "Error: Expect the environment variable $$ROOT to point to the Desktop installation")
+endif
+
+APP_NAME = pig
+include $(ROOT)/Makefile.sdk

+ 2 - 0
apps/pig/babel.cfg

@@ -0,0 +1,2 @@
+[python: src/pig/**.py]
+[mako: src/pig/templates/**.mako]

+ 20 - 0
apps/pig/hueversion.py

@@ -0,0 +1,20 @@
+# Licensed to Cloudera, Inc. under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  Cloudera, Inc. 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.
+#
+# This file should be the one source of truth for for versions within HUE.
+# It is at least included by each of the default hue app's setup.py.
+
+VERSION="2.1.0"

+ 29 - 0
apps/pig/setup.py

@@ -0,0 +1,29 @@
+# Licensed to Cloudera, Inc. under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  Cloudera, Inc. 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.
+from setuptools import setup, find_packages
+from hueversion import VERSION
+
+setup(
+      name = "pig",
+      version = VERSION,
+      author = "Hue",
+      url = 'http://github.com/cloudera/hue',
+      description = "Demos on how to collect, process and anlyse Big Data",
+      packages = find_packages('src'),
+      package_dir = {'': 'src'},
+      install_requires = ['setuptools', 'desktop'],
+      entry_points = { 'desktop.sdk.application': 'pig=pig' },
+)

+ 15 - 0
apps/pig/src/pig/__init__.py

@@ -0,0 +1,15 @@
+# Licensed to Cloudera, Inc. under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  Cloudera, Inc. 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.

+ 84 - 0
apps/pig/src/pig/api.py

@@ -0,0 +1,84 @@
+#!/usr/bin/env python
+# Licensed to Cloudera, Inc. under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  Cloudera, Inc. 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.
+
+import logging
+import re
+
+from django.utils.translation import ugettext as _
+
+from jobbrowser.views import job_single_logs
+from oozie.models import Workflow, Pig
+from oozie.views.editor import _submit_workflow
+
+
+LOG = logging.getLogger(__name__)
+
+
+class Api:
+  WORKFLOW_NAME = 'pig-app-hue-script'
+  RE_LOGS = re.compile('>>> Invoking Pig command line now >>>'
+                       '\n\n\nRun pig script using PigRunner.run\(\) for Pig version .+?\n'
+                       '(?P<pig>.*?)'
+                       '(<<< Invocation of Pig command completed <<<|<<< Invocation of Main class completed)', re.DOTALL | re.M)
+  
+  def __init__(self, fs, user):
+    self.fs = fs
+    self.user = user
+    
+  def submit(self, pig_script, mapping):    
+    workflow = Workflow.objects.new_workflow(self.user)
+    workflow.name = Api.WORKFLOW_NAME
+    workflow.is_history = True
+    workflow.save()
+    Workflow.objects.initialize(workflow, self.fs)
+    
+    script_path = workflow.deployment_dir + '/script.pig'
+    self.fs.create(script_path, data=pig_script.dict['script'])
+    
+    action = Pig.objects.create(name='pig', script_path=script_path, workflow=workflow, node_type='pig')
+    action.add_node(workflow.end)
+    
+    start_link = workflow.start.get_link()
+    start_link.child = action
+    start_link.save()    
+    
+    return _submit_workflow(self.user, self.fs, workflow, mapping)
+  
+  def get_log(self, request, oozie_workflow):    
+    logs = {}
+  
+    for action in oozie_workflow.get_working_actions():
+      try:
+        if action.externalId:
+          log = job_single_logs(request, **{'job': action.externalId})  
+          if log:
+            logs[action.name] = Api.RE_LOGS.search(log['logs'][1]).group(1)
+      except Exception, e:
+        LOG.error('An error happen while watching the demo running: %(error)s' % {'error': e})
+  
+    workflow_actions = []
+    
+    if oozie_workflow.get_working_actions():
+      for action in oozie_workflow.get_working_actions():
+        appendable = {
+          'name': action.name,
+          'status': action.status,
+          'logs': logs.get(action.name, '')
+        }
+        workflow_actions.append(appendable)   
+      
+    return logs, workflow_actions 

+ 40 - 0
apps/pig/src/pig/conf.py

@@ -0,0 +1,40 @@
+#!/usr/bin/env python
+# Licensed to Cloudera, Inc. under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  Cloudera, Inc. 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.
+
+from os.path import dirname, join
+from django.utils.translation import ugettext_lazy as _
+
+from desktop.lib.conf import Config
+
+
+# TODO update hue.inis
+
+REPO_PROTOCOL = Config(
+  key="repo_protocol",
+  help=_("Protocol of the repository URI (e.g. 'http://, file://)."),
+  default='http://')
+
+REPO_URI = Config(
+  key="repo_uri",
+  # TODO remove
+  default=join(dirname(__file__), "..", "..", "src/pig/test_data/test-repo"),
+  help=_("Path of the repository to fetch."))
+
+HDFS_WORKSPACE = Config(
+  key="hdfs_workspace",
+  default="/tmp",
+  help=_("Where to upload the demo and save their outputs."))

+ 20 - 0
apps/pig/src/pig/forms.py

@@ -0,0 +1,20 @@
+#!/usr/bin/env python
+# Licensed to Cloudera, Inc. under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  Cloudera, Inc. 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.
+
+
+from django import forms
+

+ 35 - 0
apps/pig/src/pig/locale/de/LC_MESSAGES/django.po

@@ -0,0 +1,35 @@
+# German translations for Hue.
+# Copyright (C) 2012 Cloudera
+# This file is distributed under the same license as the Hue project.
+# FIRST AUTHOR <EMAIL@ADDRESS>, 2012.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: PROJECT VERSION\n"
+"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
+"POT-Creation-Date: 2012-09-11 13:35-0700\n"
+"PO-Revision-Date: 2012-07-30 18:50-0700\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: de <LL@li.org>\n"
+"Plural-Forms: nplurals=2; plural=(n != 1)\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=utf-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Generated-By: Babel 0.9.6\n"
+
+#: src/about/templates/index.mako:20
+msgid "About Hue"
+msgstr "Über Hue"
+
+#: src/about/templates/index.mako:25
+msgid "Configuration"
+msgstr "Konfiguration"
+
+#: src/about/templates/index.mako:26
+msgid "Check for misconfiguration"
+msgstr "Auf Fehlkonfiguration prüfen"
+
+#: src/about/templates/index.mako:27
+msgid "Server Logs"
+msgstr "Server-Protokolle"
+

+ 35 - 0
apps/pig/src/pig/locale/en_US.pot

@@ -0,0 +1,35 @@
+# Translations template for Hue.
+# Copyright (C) 2012 Cloudera, Inc
+# This file is distributed under the same license as the Hue project.
+# FIRST AUTHOR <EMAIL@ADDRESS>, 2012.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: Hue VERSION\n"
+"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
+"POT-Creation-Date: 2012-09-11 13:35-0700\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=utf-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Generated-By: Babel 0.9.6\n"
+
+#: src/about/templates/index.mako:20
+msgid "About Hue"
+msgstr ""
+
+#: src/about/templates/index.mako:25
+msgid "Configuration"
+msgstr ""
+
+#: src/about/templates/index.mako:26
+msgid "Check for misconfiguration"
+msgstr ""
+
+#: src/about/templates/index.mako:27
+msgid "Server Logs"
+msgstr ""
+

+ 35 - 0
apps/pig/src/pig/locale/en_US.pot~

@@ -0,0 +1,35 @@
+# Translations template for Hue.
+# Copyright (C) 2012 Cloudera, Inc
+# This file is distributed under the same license as the Hue project.
+# FIRST AUTHOR <EMAIL@ADDRESS>, 2012.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: Hue VERSION\n"
+"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
+"POT-Creation-Date: 2012-07-31 11:34-0700\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=utf-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Generated-By: Babel 0.9.6\n"
+
+#: src/about/templates/index.mako:20
+msgid "About Hue"
+msgstr ""
+
+#: src/about/templates/index.mako:25
+msgid "Configuration"
+msgstr ""
+
+#: src/about/templates/index.mako:26
+msgid "Check for misconfiguration"
+msgstr ""
+
+#: src/about/templates/index.mako:27
+msgid "Server Logs"
+msgstr ""
+

+ 35 - 0
apps/pig/src/pig/locale/es/LC_MESSAGES/django.po

@@ -0,0 +1,35 @@
+# Spanish translations for Hue.
+# Copyright (C) 2012 Cloudera
+# This file is distributed under the same license as the Hue project.
+# FIRST AUTHOR <EMAIL@ADDRESS>, 2012.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: PROJECT VERSION\n"
+"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
+"POT-Creation-Date: 2012-09-11 13:35-0700\n"
+"PO-Revision-Date: 2012-07-30 18:50-0700\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: es <LL@li.org>\n"
+"Plural-Forms: nplurals=2; plural=(n != 1)\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=utf-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Generated-By: Babel 0.9.6\n"
+
+#: src/about/templates/index.mako:20
+msgid "About Hue"
+msgstr "Acerca de Hue"
+
+#: src/about/templates/index.mako:25
+msgid "Configuration"
+msgstr "Configuración"
+
+#: src/about/templates/index.mako:26
+msgid "Check for misconfiguration"
+msgstr "Comprobar error de configuración"
+
+#: src/about/templates/index.mako:27
+msgid "Server Logs"
+msgstr "Registros del servidor"
+

+ 35 - 0
apps/pig/src/pig/locale/fr/LC_MESSAGES/django.po

@@ -0,0 +1,35 @@
+# French translations for Hue.
+# Copyright (C) 2012 Cloudera
+# This file is distributed under the same license as the Hue project.
+# FIRST AUTHOR <EMAIL@ADDRESS>, 2012.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: PROJECT VERSION\n"
+"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
+"POT-Creation-Date: 2012-09-11 13:35-0700\n"
+"PO-Revision-Date: 2012-07-30 18:50-0700\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: fr <LL@li.org>\n"
+"Plural-Forms: nplurals=2; plural=(n > 1)\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=utf-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Generated-By: Babel 0.9.6\n"
+
+#: src/about/templates/index.mako:20
+msgid "About Hue"
+msgstr "A propos de Hue"
+
+#: src/about/templates/index.mako:25
+msgid "Configuration"
+msgstr "Configuration"
+
+#: src/about/templates/index.mako:26
+msgid "Check for misconfiguration"
+msgstr "Recherche de configuration incorrecte"
+
+#: src/about/templates/index.mako:27
+msgid "Server Logs"
+msgstr "Journaux de serveur"
+

+ 35 - 0
apps/pig/src/pig/locale/ja/LC_MESSAGES/django.po

@@ -0,0 +1,35 @@
+# Japanese translations for Hue.
+# Copyright (C) 2012 Cloudera
+# This file is distributed under the same license as the Hue project.
+# FIRST AUTHOR <EMAIL@ADDRESS>, 2012.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: PROJECT VERSION\n"
+"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
+"POT-Creation-Date: 2012-09-11 13:35-0700\n"
+"PO-Revision-Date: 2012-07-30 18:50-0700\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: ja <LL@li.org>\n"
+"Plural-Forms: nplurals=1; plural=0\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=utf-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Generated-By: Babel 0.9.6\n"
+
+#: src/about/templates/index.mako:20
+msgid "About Hue"
+msgstr "Hue のバージョン情報"
+
+#: src/about/templates/index.mako:25
+msgid "Configuration"
+msgstr "設定"
+
+#: src/about/templates/index.mako:26
+msgid "Check for misconfiguration"
+msgstr "誤設定がないか確認します"
+
+#: src/about/templates/index.mako:27
+msgid "Server Logs"
+msgstr "サーバーログ"
+

+ 35 - 0
apps/pig/src/pig/locale/ko/LC_MESSAGES/django.po

@@ -0,0 +1,35 @@
+# Korean translations for Hue.
+# Copyright (C) 2012 Cloudera
+# This file is distributed under the same license as the Hue project.
+# FIRST AUTHOR <EMAIL@ADDRESS>, 2012.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: PROJECT VERSION\n"
+"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
+"POT-Creation-Date: 2012-09-11 13:35-0700\n"
+"PO-Revision-Date: 2012-07-30 18:50-0700\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: ko <LL@li.org>\n"
+"Plural-Forms: nplurals=1; plural=0\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=utf-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Generated-By: Babel 0.9.6\n"
+
+#: src/about/templates/index.mako:20
+msgid "About Hue"
+msgstr "Hue 정보"
+
+#: src/about/templates/index.mako:25
+msgid "Configuration"
+msgstr "구성"
+
+#: src/about/templates/index.mako:26
+msgid "Check for misconfiguration"
+msgstr "잘못된 구성 검사"
+
+#: src/about/templates/index.mako:27
+msgid "Server Logs"
+msgstr "서버 로그"
+

+ 35 - 0
apps/pig/src/pig/locale/pt/LC_MESSAGES/django.po

@@ -0,0 +1,35 @@
+# Portuguese translations for Hue.
+# Copyright (C) 2012 Cloudera
+# This file is distributed under the same license as the Hue project.
+# FIRST AUTHOR <EMAIL@ADDRESS>, 2012.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: PROJECT VERSION\n"
+"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
+"POT-Creation-Date: 2012-09-11 13:35-0700\n"
+"PO-Revision-Date: 2012-07-30 18:50-0700\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: pt <LL@li.org>\n"
+"Plural-Forms: nplurals=2; plural=(n != 1)\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=utf-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Generated-By: Babel 0.9.6\n"
+
+#: src/about/templates/index.mako:20
+msgid "About Hue"
+msgstr "Acerca da Hue"
+
+#: src/about/templates/index.mako:25
+msgid "Configuration"
+msgstr "Configuração"
+
+#: src/about/templates/index.mako:26
+msgid "Check for misconfiguration"
+msgstr "Verifique se a configuração está correcta"
+
+#: src/about/templates/index.mako:27
+msgid "Server Logs"
+msgstr "Registos do servidor"
+

+ 35 - 0
apps/pig/src/pig/locale/pt_BR/LC_MESSAGES/django.po

@@ -0,0 +1,35 @@
+# Portuguese (Brazil) translations for Hue.
+# Copyright (C) 2012 Cloudera
+# This file is distributed under the same license as the Hue project.
+# FIRST AUTHOR <EMAIL@ADDRESS>, 2012.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: PROJECT VERSION\n"
+"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
+"POT-Creation-Date: 2012-09-11 13:35-0700\n"
+"PO-Revision-Date: 2012-07-30 18:50-0700\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: pt_BR <LL@li.org>\n"
+"Plural-Forms: nplurals=2; plural=(n > 1)\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=utf-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Generated-By: Babel 0.9.6\n"
+
+#: src/about/templates/index.mako:20
+msgid "About Hue"
+msgstr "Sobre o Hue"
+
+#: src/about/templates/index.mako:25
+msgid "Configuration"
+msgstr "Configuração"
+
+#: src/about/templates/index.mako:26
+msgid "Check for misconfiguration"
+msgstr "Verificar configurações incorretas"
+
+#: src/about/templates/index.mako:27
+msgid "Server Logs"
+msgstr "Logs de servidor"
+

+ 35 - 0
apps/pig/src/pig/locale/zh_CN/LC_MESSAGES/django.po

@@ -0,0 +1,35 @@
+# Chinese (China) translations for Hue.
+# Copyright (C) 2012 Cloudera
+# This file is distributed under the same license as the Hue project.
+# FIRST AUTHOR <EMAIL@ADDRESS>, 2012.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: PROJECT VERSION\n"
+"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
+"POT-Creation-Date: 2012-09-11 13:35-0700\n"
+"PO-Revision-Date: 2012-07-30 18:50-0700\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: zh_CN <LL@li.org>\n"
+"Plural-Forms: nplurals=1; plural=0\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=utf-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Generated-By: Babel 0.9.6\n"
+
+#: src/about/templates/index.mako:20
+msgid "About Hue"
+msgstr "关于 Hue"
+
+#: src/about/templates/index.mako:25
+msgid "Configuration"
+msgstr "配置"
+
+#: src/about/templates/index.mako:26
+msgid "Check for misconfiguration"
+msgstr "检查错误配置"
+
+#: src/about/templates/index.mako:27
+msgid "Server Logs"
+msgstr "服务器日志"
+

+ 89 - 0
apps/pig/src/pig/models.py

@@ -0,0 +1,89 @@
+#!/usr/bin/env python
+# Licensed to Cloudera, Inc. under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  Cloudera, Inc. 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.
+
+
+try:
+  import json
+except ImportError:
+  import simplejson as json
+import posixpath
+
+from hadoop.fs.hadoopfs import Hdfs
+from django.db import models
+from django.contrib.auth.models import User
+from django.utils.translation import ugettext as _, ugettext_lazy as _t
+
+from oozie.models import Workflow
+
+
+# To move somewhere else when official commit
+class Document(models.Model):
+  owner = models.ForeignKey(User, db_index=True, verbose_name=_t('Owner'), help_text=_t('Person who can modify the job.'))
+  is_history = models.BooleanField(default=False, db_index=True, verbose_name=_t('Is managed'),
+                                  help_text=_t('If the job should show up in the history'))
+
+
+class PigScript(Document):
+  _ATTRIBUTES = ['script', 'properties']
+  
+  data = models.TextField(default=json.dumps({'script': ''}))
+    
+  def update_from_dict(self, attrs):
+    data_dict = self.dict
+    
+    if attrs.get('script'):
+      data_dict['script'] = attrs['script']
+
+    self.data = json.dumps(data_dict)
+    
+  @property
+  def dict(self):
+    return json.loads(self.data)
+  
+  
+class Submission(models.Model):
+  script = models.ForeignKey(PigScript)
+  workflow = models.ForeignKey(Workflow)
+  
+
+class Udf:
+  pass
+
+
+def get_workflow_output(oozie_workflow, fs):
+  output = None
+
+  if 'workflowRoot' in oozie_workflow.conf_dict:
+    output = oozie_workflow.conf_dict.get('workflowRoot')
+    if output and not fs.exists(output):
+      output = None
+
+  return output
+
+
+def hdfs_link(url):
+  if url:
+    path = Hdfs.urlsplit(url)[2]
+    if path:
+      if path.startswith(posixpath.sep):
+        return "/filebrowser/view" + path
+      else:
+        return "/filebrowser/home_relative_view/" + path
+    else:
+      return url
+  else:
+    return url

+ 22 - 0
apps/pig/src/pig/settings.py

@@ -0,0 +1,22 @@
+# Licensed to Cloudera, Inc. under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  Cloudera, Inc. 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.
+DJANGO_APPS = ['pig']
+NICE_NAME = 'Pig'
+MENU_INDEX = 12
+ICON = '/pig/static/art/icon_pig_24.ico'
+
+REQUIRES_HADOOP = False
+IS_URL_NAMESPACED = True

+ 48 - 0
apps/pig/src/pig/templates/dashboard.mako

@@ -0,0 +1,48 @@
+## Licensed to Cloudera, Inc. under one
+## or more contributor license agreements.  See the NOTICE file
+## distributed with this work for additional information
+## regarding copyright ownership.  Cloudera, Inc. 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.
+<%!
+from desktop.views import commonheader, commonfooter
+from django.utils.translation import ugettext as _
+%>
+
+<%namespace name="navigation" file="navigation-bar.inc.mako" />
+<%namespace name="utils" file="utils.inc.mako" />
+
+${ commonheader(_('Pig'), "pig", user, "100px") | n,unicode }
+
+
+<div class="container-fluid">
+   ${ navigation.menubar(section='dashboard') }
+  
+    <div class="tab-content">
+      <div class="tab-pane active">
+
+		<div class="container-fluid">
+		    <div class="row-fluid">                  
+		       % for workflow in workflows.jobs:
+		         ${ workflow } </br>
+		       % endfor
+		    </div>
+		</div>
+
+   
+      </div>
+
+    </div>
+  </div>
+</div>
+
+${ commonfooter(messages) | n,unicode }

+ 190 - 0
apps/pig/src/pig/templates/editor.mako

@@ -0,0 +1,190 @@
+## Licensed to Cloudera, Inc. under one
+## or more contributor license agreements.  See the NOTICE file
+## distributed with this work for additional information
+## regarding copyright ownership.  Cloudera, Inc. 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.
+<%!
+from desktop.views import commonheader, commonfooter
+from django.utils.translation import ugettext as _
+%>
+
+<%namespace name="navigation" file="navigation-bar.inc.mako" />
+<%namespace name="utils" file="utils.inc.mako" />
+
+${ commonheader(_('Pig'), "pig", user, "100px") | n,unicode }
+
+<script src="/static/ext/js/datatables-paging-0.1.js" type="text/javascript" charset="utf-8"></script>
+<script src="/static/ext/js/knockout-2.1.0.js" type="text/javascript" charset="utf-8"></script>
+<script src="/static/ext/js/moment.min.js" type="text/javascript" charset="utf-8"></script>
+<script src="/pig/static/js/pig.ko.js" type="text/javascript" charset="utf-8"></script>
+<script src="/static/ext/js/routie-0.3.0.min.js" type="text/javascript" charset="utf-8"></script>
+
+<div class="container-fluid">
+  ${ navigation.menubar(section='editor') }
+  
+</div>
+
+<br/>
+
+<div class="container-fluid">
+    <div class="row-fluid">
+        <div class="span3">
+            <div class="well sidebar-nav">
+                <form id="advancedSettingsForm" method="POST" class="form form-horizontal noPadding">
+                    <ul class="nav nav-list">
+                        <li class="nav-header">${_('Editor')}</li>
+                        <li class="active"><a href="#editor">${ _('Edit script') }</a></li>                        
+                        <li class="nav-header">${_('Properties')}</li>
+                        <li><a href="#edit-properties">${ _('Edit properties') }</a></li>
+                        ##<li class="nav-header">${_('UDF')}</li>
+                        ##<li><a href="#createDataset">${ _('New') }</a></li>
+                        ##<li><a href="#createDataset">${ _('Add') }</a></li>
+                        <li class="nav-header">${_('Actions')}</li>
+                        <li>
+                          <a href="#save" title="${ _('Save the script') }" rel="tooltip" data-placement="right">
+                            <i class="icon-save"></i> ${ _('Save') }
+                          </a>
+                        </li>                            
+                        <li>
+                          <a id="clone-btn" href="javascript:void(0)" data-clone-url="" title="${ _('Copy the script') }" rel="tooltip" data-placement="right">
+                            <i class="icon-retweet"></i> ${ _('Copy') }
+                          </a>
+                        </li>
+                    </ul>
+                </form>
+            </div>
+        </div>
+
+        <div id="editor" class="section span9">
+          <h1>${_('Editor')}</h1>
+            <ul class="nav nav nav-pills">
+              <li class="active"><a href="#pig" data-toggle="tab">${ _('Pig') }</a></li>
+            </ul>                  
+		    <form id="queryForm">
+		      <textarea class="span11" rows="20" placeholder="A = LOAD '/user/${ user }/data';" name="script" id="script"></textarea>
+		    </form>
+            <br/>
+        </div>
+        
+        <div id="edit-properties" class="section hide span9">
+          <div class="alert alert-info"><h3>${ _('Edit properties') }</h3></div>
+          <div id="edit-properties-body">
+            None for now
+          </div>
+          <div class="form-actions">
+            <a href="#" class="btn btn-primary" id="add-dataset-btn">${ _('Save') }</a>
+          </div>
+        </div>        
+        
+      </div>
+   </div>
+
+    <div data-bind="visible: isLoading()">
+      <img src="/static/art/spinner.gif"/>
+    </div>
+    <div class="alert" data-bind="visible: apps().length == 0  && !isLoading()">
+      ${ _('Sorry, there are no editor matching the search criteria.') }
+    </div>
+    <div data-bind="template: {name: 'appTemplate', foreach: apps}"></div>
+  </div>
+
+    </div>
+  </div>
+</div>
+
+
+<script id="appTemplate" type="text/html">
+  <div class="appWidget" data-bind="css: {isRunning: isRunning()}">
+    <div class="appWidgetHeader">
+      <div class="row-fluid">
+        <div class="span11">
+          <h4>
+            <span data-bind="text: name"></span>
+            <img src="/static/art/spinner.gif" data-bind="visible: isRunning()" align="middle" style="margin-left: 14px"/>
+          </h4>
+          <p data-bind="text: description"></p>
+          <div data-bind="visible: output() != '' && output() != null" style="margin-bottom:6px">
+            <a data-bind="attr: {'href': output(), 'target': '_blank'}"><i class="icon-file"></i> ${ _('Output') }</a>
+          </div>
+        </div>
+        <div class="span1 shortcuts">
+          <a class="shortcut" data-bind="click: $root.manageApp, attr: {'title': tooltip()}" rel="tooltip">
+            <i data-bind="css: {'shortcutIcon': name != '', 'icon-play': status() == '' || status() == 'STOPPED' || status() == 'SUCCEEDED', 'icon-stop': status() == 'RUNNING'}"></i>
+          </a>
+        </div>
+      </div>
+    </div>
+    <div data-bind="visible: name != '', css: {'demoProgress': progress() != '', 'running': status() == 'RUNNING', 'succeeded': status() == 'SUCCEEDED', 'failed': status() == 'FAILED' || status() == 'STOPPED'}, attr: { style: progressCss }"></div>
+    <div class="appWidgetContent" data-bind="visible: status() != ''">
+      <div data-bind="foreach: actions">
+        <div data-bind="css: {'action': name != '' ,'running': status == 'RUNNING' || status == 'PREP', 'succeeded': status == 'OK', 'failed': status == 'FAILED' || $parent.status() == 'STOPPED'}">
+          <img src="/static/art/spinner.gif"
+               data-bind="visible: (status == 'RUNNING' || status == 'PREP') && $parent.isRunning()" class="pull-right"
+               style="margin-right: 10px;margin-top:10px"/>
+          <h6 data-bind="text: name"></h6>
+        </div>
+        ## scroll to top + go up or 'Log' tab?
+        <pre data-bind="text: logs, visible: logs.length > 0"></pre>
+      </div>
+    </div>
+  </div>
+</script>
+
+
+<link rel="stylesheet" href="/pig/static/css/pig.css">
+
+<script type="text/javascript" charset="utf-8">
+  $(document).ready(function () {
+    var LABELS = {
+      KILL_ERROR:"${ _('The pig job could not be killed.') }",
+      TOOLTIP_PLAY:"${ _('Run this pig script') }",
+      TOOLTIP_STOP:"${ _('Stop the execution') }",
+      SAVED:"${ _('Saved') }",
+    }
+    
+    var viewModel = new pigModel("${ url('pig:load_script') }", LABELS);
+    ko.applyBindings(viewModel);
+
+    viewModel.retrieveData();
+
+    $(document).bind("updateTooltips", function () {
+      $("a[rel=tooltip]").tooltip("destroy");
+      $("a[rel=tooltip]").tooltip();
+    });
+  
+    function showSection(section) {
+      $(".section").hide();
+      $("#" + section).show();
+      highlightMenu(section);
+    }
+       
+    function highlightMenu(section) {
+      $(".nav-list li").removeClass("active");
+      $("a[href='#" + section + "']").parent().addClass("active");
+    }       
+          
+    routie({
+      "editor":function () {
+        showSection("editor");
+      },
+      "edit-properties":function () {
+        showSection("edit-properties");
+      },
+      "save":function () {
+	    viewModel.save();
+      }      
+    });    
+  });
+</script>
+
+${ commonfooter(messages) | n,unicode }

+ 33 - 0
apps/pig/src/pig/templates/navigation-bar.inc.mako

@@ -0,0 +1,33 @@
+## Licensed to Cloudera, Inc. under one
+## or more contributor license agreements.  See the NOTICE file
+## distributed with this work for additional information
+## regarding copyright ownership.  Cloudera, Inc. 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.
+
+<%!
+  from django.utils.translation import ugettext as _
+%>
+
+<%namespace name="utils" file="utils.inc.mako" />
+
+
+<%def name="menubar(section='')">
+  <div class="subnav subnav-fixed">
+    <ul class="nav nav nav-pills">
+      <li class="${utils.is_selected(section, 'editor')}"><a href="${ url('pig:editor') }">${ _('Editor') }</a></li>
+      <li class="${utils.is_selected(section, 'scripts')}"><a href="${ url('pig:scripts') }">${ _('Scripts') }</a></li>
+      <li class="${utils.is_selected(section, 'dashboard')}"><a href="${ url('pig:dashboard') }">${ _('Dashboard') }</a></li>
+      ##<li class="${utils.is_selected(section, 'udfs')}"><a href="${ url('pig:udfs') }">${ _('UDF') }</a></li>
+    </ul>
+  </div>
+</%def>

+ 50 - 0
apps/pig/src/pig/templates/scripts.mako

@@ -0,0 +1,50 @@
+## Licensed to Cloudera, Inc. under one
+## or more contributor license agreements.  See the NOTICE file
+## distributed with this work for additional information
+## regarding copyright ownership.  Cloudera, Inc. 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.
+<%!
+from desktop.views import commonheader, commonfooter
+from django.utils.translation import ugettext as _
+%>
+
+<%namespace name="navigation" file="navigation-bar.inc.mako" />
+<%namespace name="utils" file="utils.inc.mako" />
+
+${ commonheader(_('Pig'), "pig", user, "100px") | n,unicode }
+
+
+<div class="container-fluid">
+   ${ navigation.menubar(section='scripts') }
+  
+    <div class="tab-content">
+      <div class="tab-pane active">
+
+		<div class="container-fluid">
+		    <div class="row-fluid">    
+		      Scripts
+		      </br>
+               % for script in scripts:
+                 ${ script } </br>
+               % endfor
+		    </div>
+		</div>
+
+   
+      </div>
+
+    </div>
+  </div>
+</div>
+
+${ commonfooter(messages) | n,unicode }

+ 46 - 0
apps/pig/src/pig/templates/udfs.mako

@@ -0,0 +1,46 @@
+## Licensed to Cloudera, Inc. under one
+## or more contributor license agreements.  See the NOTICE file
+## distributed with this work for additional information
+## regarding copyright ownership.  Cloudera, Inc. 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.
+<%!
+from desktop.views import commonheader, commonfooter
+from django.utils.translation import ugettext as _
+%>
+
+<%namespace name="navigation" file="navigation-bar.inc.mako" />
+<%namespace name="utils" file="utils.inc.mako" />
+
+${ commonheader(_('Pig'), "pig", user, "100px") | n,unicode }
+
+
+<div class="container-fluid">
+   ${ navigation.menubar(section='udfs') }
+  
+    <div class="tab-content">
+      <div class="tab-pane active">
+
+		<div class="container-fluid">
+		    <div class="row-fluid">         
+		      No UDFS         
+		    </div>
+		</div>
+
+   
+      </div>
+
+    </div>
+  </div>
+</div>
+
+${ commonfooter(messages) | n,unicode }

+ 24 - 0
apps/pig/src/pig/templates/utils.inc.mako

@@ -0,0 +1,24 @@
+## Licensed to Cloudera, Inc. under one
+## or more contributor license agreements.  See the NOTICE file
+## distributed with this work for additional information
+## regarding copyright ownership.  Cloudera, Inc. 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.
+
+<%def name="is_selected(section, matcher)">
+  <%
+    if section == matcher:
+      return "active"
+    else:
+      return ""
+  %>
+</%def>

+ 16 - 0
apps/pig/src/pig/tests.py

@@ -0,0 +1,16 @@
+#!/usr/bin/env python
+# Licensed to Cloudera, Inc. under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  Cloudera, Inc. 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.

+ 33 - 0
apps/pig/src/pig/urls.py

@@ -0,0 +1,33 @@
+#!/usr/bin/env python
+# Licensed to Cloudera, Inc. under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  Cloudera, Inc. 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.
+
+from django.conf.urls.defaults import patterns, url
+
+urlpatterns = patterns('pig.views',
+  url(r'^$', 'editor', name='index'),
+
+  url(r'^editor/$', 'editor', name='editor'),
+  url(r'^dashboard/$', 'dashboard', name='dashboard'),
+  url(r'^scripts/$', 'scripts', name='scripts'),
+  url(r'^udfs/$', 'udfs', name='udfs'),
+
+  # Ajax
+  url(r'^load_script/(?P<doc_id>\d+)?', 'load_script', name='load_script'),
+  url(r'^save(?P<doc_id>[\w\.]+)', 'save', name='save'),
+  url(r'^submit/(?P<doc_id>[\w\.]+)$', 'submit', name='submit'),
+  url(r'^watch/(?P<doc_id>[\w\.]+)/(?P<job_id>[-\w]+)$', 'watch', name='watch')
+)

+ 158 - 0
apps/pig/src/pig/views.py

@@ -0,0 +1,158 @@
+#!/usr/bin/env python
+# Licensed to Cloudera, Inc. under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  Cloudera, Inc. 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.
+
+try:
+  import json
+except ImportError:
+  import simplejson as json
+import logging
+
+from django.core.urlresolvers import reverse
+from django.utils.translation import ugettext as _
+from django.views.decorators.http import require_http_methods
+from django.http import HttpResponse
+
+from desktop.lib.django_util import render
+from desktop.lib.exceptions_renderable import PopupException
+from liboozie.oozie_api import get_oozie
+from oozie.views.dashboard import show_oozie_error, check_job_access_permission
+
+from pig.api import Api
+from pig.models import get_workflow_output, hdfs_link, PigScript
+
+
+LOG = logging.getLogger(__name__)
+
+
+def editor(request):
+  pig_script_json = {}
+  return render('editor.mako', request, {
+                  'pig_script_json': json.dumps(pig_script_json)
+                  }
+                )
+
+@show_oozie_error
+def dashboard(request):
+  kwargs = {'cnt': 100,}
+  kwargs['user'] = request.user.username
+  kwargs['name'] = Api.WORKFLOW_NAME
+
+  workflows = get_oozie().get_workflows(**kwargs)
+    
+  return render('dashboard.mako', request, {
+                    'workflows': workflows
+                  }
+                )
+
+def scripts(request):
+  
+  return render('scripts.mako', request, {
+                    'scripts': PigScript.objects.filter(is_history=False)
+                  }
+                )
+
+
+def udfs(request):
+  
+  return render('udfs.mako', request, {
+                  }
+                )
+
+
+def load_script(request, doc_id):
+
+  ko_repo = {
+    'id': doc_id,
+    'name': 'Run',
+    'description': 'Outputs and MR jobs',
+    'submitUrl': reverse('pig:submit', args=[doc_id]),
+    'saveUrl': reverse('pig:save', args=[doc_id])
+    }
+
+  response = {
+    'apps': [ko_repo],
+    'repo_id': 1,
+  }
+
+  return HttpResponse(json.dumps(response), content_type="text/plain")
+
+
+@require_http_methods(["POST"])
+def save(request, doc_id=None):
+  # TODO security
+  if doc_id is None:
+    script = request.POST.get('script')
+    pig_script = PigScript.objects.create(owner=request.user)
+  pig_script.update_from_dict({'script': script})
+  pig_script.save()
+  
+  response = {
+    'doc_id': pig_script.id,
+  }
+
+  return HttpResponse(json.dumps(response), content_type="text/plain")
+
+
+@require_http_methods(["POST"])
+@show_oozie_error
+def submit(request, doc_id):
+  # TODO security
+  script = request.POST.get('script')
+  pig_script = PigScript.objects.create(owner=request.user, is_history=True)
+  pig_script.update_from_dict({'script': script})
+  pig_script.save()
+  
+  # Todo, will come from script properties later
+  mapping = {
+    'oozie.use.system.libpath':  'true',
+  }  
+
+  oozie_id = Api(request.fs, request.user).submit(pig_script, mapping)
+
+  response = {
+    'demoId': doc_id,
+    'jobId': pig_script.id,
+    'watchUrl': reverse('pig:watch', kwargs={'doc_id': doc_id, 'job_id': oozie_id}) + '?format=python'
+  }
+
+  return HttpResponse(json.dumps(response), content_type="text/plain")
+
+
+@show_oozie_error
+def watch(request, doc_id, job_id):
+  oozie_workflow = check_job_access_permission(request, job_id) 
+  logs, workflow_actions = Api(request, job_id).get_log(request, oozie_workflow)
+  output = get_workflow_output(oozie_workflow, request.fs)
+
+  workflow = {
+    'job_id': oozie_workflow.id,
+    'status': oozie_workflow.status,
+    'progress': oozie_workflow.get_progress(),
+    'isRunning': oozie_workflow.is_running(),
+    'killUrl': reverse('oozie:manage_oozie_jobs', kwargs={'job_id': oozie_workflow.id, 'action': 'kill'}),
+    'rerunUrl': reverse('oozie:rerun_oozie_job', kwargs={'job_id': oozie_workflow.id, 'app_path': oozie_workflow.appPath}),
+    'actions': workflow_actions
+  }
+
+  response = {
+    'workflow': workflow,
+    'logs': logs,
+    'output': hdfs_link(output)
+  }
+  
+  return HttpResponse(json.dumps(response), content_type="text/plain")
+

BIN
apps/pig/static/art/icon_pig_24.ico


+ 117 - 0
apps/pig/static/css/pig.css

@@ -0,0 +1,117 @@
+body {
+  padding-top: 60px;
+}
+
+.appWidget {
+  margin: 10px auto 5px auto;
+  background-color: #FFFFFF;
+}
+
+.appWidgetHeader {
+  background: #FAFAFA;
+  border: 1px solid #D5D5D5;
+  -webkit-border-top-left-radius: 4px;
+  -webkit-border-top-right-radius: 4px;
+  -moz-border-radius-topleft: 4px;
+  -moz-border-radius-topright: 4px;
+  border-top-left-radius: 4px;
+  border-top-right-radius: 4px;
+  -webkit-background-clip: padding-box;
+  padding-left: 10px;
+}
+
+.appWidget:nth-child(even) .appWidgetHeader{
+  background: #F0F0F0;
+}
+
+.appWidgetHeader:hover, .appWidget:nth-child(even) .appWidgetHeader:hover {
+  background: #E8F1FB;
+}
+
+.appWidgetHeader p {
+  color: #333;
+}
+
+.appWidgetContent {
+  border: 1px solid #D5D5D5;
+  border-top: none;
+  -webkit-border-bottom-left-radius: 4px;
+  -webkit-border-bottom-right-radius: 4px;
+  -moz-border-radius-bottomleft: 4px;
+  -moz-border-radius-bottomright: 4px;
+  border-bottom-left-radius: 4px;
+  border-bottom-right-radius: 4px;
+  padding: 10px;
+  max-height: 340px;
+  overflow-y: scroll;
+}
+
+.appWidgetContent h6 {
+  padding: 10px;
+  margin: 0;
+}
+
+.appWidgetContent pre {
+  border:0;
+}
+
+.shortcuts {
+  text-align: center;
+}
+
+.shortcuts .shortcut {
+  width: 80px;
+  display: inline-block;
+  padding: 12px 0;
+  margin: 1em .9% 1em;
+  vertical-align: top;
+  text-decoration: none;
+  border-radius: 5px;
+  cursor: pointer;
+}
+
+.shortcuts .shortcut .shortcutIcon {
+  margin-right: .25em;
+  margin-bottom: .25em;
+  font-size: 60px;
+  color: #888;
+}
+
+.shortcuts .shortcut .shortcutIcon:hover {
+  color: #333;
+}
+
+.availableDemos {
+  color: #888;
+  padding-left: 6px;
+  font-size: 12px;
+  text-align: left;
+  margin-top: 14px;
+}
+
+.demoProgress {
+  height: 2px;
+}
+
+.running {
+  background-color: #faa732;
+  border-left: 2px solid #faa732;
+}
+
+.succeeded {
+  background-color: #5eb95e;
+  border-left: 2px solid #5eb95e;
+}
+
+.failed {
+  background-color: #dd514c;
+  border-left: 2px solid #dd514c;
+}
+
+.action {
+  background: #F5F5F5;
+}
+
+.tab-content, .tab-pane {
+  overflow-x: hidden;
+}

+ 3 - 0
apps/pig/static/help/index.html

@@ -0,0 +1,3 @@
+<html>
+<h1><a name="AboutHue-AboutHue"></a>About pig</h1>
+</html>

+ 194 - 0
apps/pig/static/js/pig.ko.js

@@ -0,0 +1,194 @@
+// Licensed to Cloudera, Inc. under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  Cloudera, Inc. 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.
+
+
+var App = function (app) {
+  return {
+    id:app.id,
+    name:app.name,
+    archive:app.archive,
+    submitUrl:app.submitUrl,
+    watchUrl:app.watchUrl,
+    saveUrl:app.saveUrl,
+    killUrl:"",
+    rerunUrl:"",
+    description:app.description,
+    isRunning:ko.observable(false),
+    status:ko.observable(""),
+    progress:ko.observable(""),
+    progressCss:ko.observable("width: 0%"),
+    intervalId:-1,
+    actions:ko.observableArray(),
+    output:ko.observable(""),
+    tooltip:ko.observable("")
+  }
+}
+
+var pigModel = function (serviceUrl, labels) {
+  var self = this;
+
+  self.serviceUrl = ko.observable(serviceUrl);
+  self.LABELS = labels;
+  self.apps = ko.observableArray();
+  self.history = ko.observableArray();
+  self.isLoading = ko.observable(true);
+
+  self.retrieveData = function () {
+    self.isLoading(true);
+
+    $.getJSON(self.serviceUrl() + self.getDocId(), function (data) {
+      self.apps(ko.utils.arrayMap(data.apps, function (app) {
+        return getInitApp(app);
+      }));
+      self.isLoading(false);
+      if ($){
+        $(document).trigger("updateTooltips");
+      }
+    });
+
+    function getInitApp(app) {
+      var a = new App(app);
+      a.tooltip(self.LABELS.TOOLTIP_PLAY);
+      return a;
+    }
+  };
+  
+  self.getDocId = function() {
+    var hash = window.location.hash;
+    var jobId = ""
+    if (hash != null && hash.indexOf("/") > -1) {
+      jobId = hash.substring(hash.indexOf("/") + 1);
+    }
+    return jobId;
+  }
+
+  self.manageApp = function (app) {
+    if (app.status() == "" || app.status() == "FAILED" || app.status() == "STOPPED") {
+      self.submitApp(app);
+    }
+    if (app.isRunning()) {
+      self.killApp(app);
+    }
+    if (app.status() == "SUCCEEDED") {
+      self.rerunApp(app);
+    }
+  };
+
+  self.submitApp = function (app) {
+    $.post(app.submitUrl, $("#queryForm").serialize(), function (data) {
+      window.location.hash = "#/" + data.jobId;
+      app.watchUrl = data.watchUrl;
+      self.updateAppStatus(app);
+      app.intervalId = window.setInterval(function () {
+        self.updateAppStatus(app);
+      }, 1000);
+    }, "json");
+  };
+
+  self.save = function (app) {
+    $.post(app.submitUrl, $("#queryForm").serialize(), function (data) {
+      if (self.getDocId() == "") {
+    	  window.location.hash += "/" + data.doc_id;  
+      }
+      $.jHueNotify.info(self.LABELS.SAVED);
+    }, "json");
+  };
+  
+  self.killApp = function (app) {
+    app.isRunning(false);
+    app.status("STOPPED");
+    app.tooltip(self.LABELS.TOOLTIP_PLAY);
+    if (app.intervalId > -1) {
+      window.clearInterval(app.intervalId);
+      self.appendToHistory(app);
+    }
+    if ($) {
+      $(document).trigger("updateTooltips");
+    }
+    if (app.killUrl) {
+      $.post(app.killUrl,function (data) {
+        if (data.status != 0) {
+          $.jHueNotify.error(data.data);
+        }
+      }, "json").error(function () {
+        $.jHueNotify.error(self.LABELS.KILL_ERROR);
+      });
+    }
+
+  };
+
+  self.rerunApp = function (app) {
+    if (app.intervalId > -1) {
+      window.clearInterval(app.intervalId);
+    }
+    self.submitApp(app);
+  };
+
+  self.updateAppStatus = function (app) {
+    $.getJSON(app.watchUrl, function (watch) {
+      var previousTooltip = app.tooltip();
+      app.tooltip(self.LABELS.TOOLTIP_STOP);
+      app.isRunning(watch.workflow.isRunning);
+      app.status(watch.workflow.status);
+      app.progress(watch.workflow.progress);
+      app.progressCss("width: " + app.progress() + "%");
+      app.actions(watch.workflow.actions);
+      app.killUrl = watch.workflow.killUrl;
+      app.rerunUrl = watch.workflow.rerunUrl;
+      app.output(watch.output);
+      if (!watch.workflow.isRunning) {
+        window.clearInterval(app.intervalId);
+        app.tooltip(self.LABELS.TOOLTIP_PLAY);
+        self.appendToHistory(app);
+      }
+      if (app.tooltip() != previousTooltip) {
+        if ($) {
+          $(document).trigger("updateTooltips");
+        }
+      }
+    });
+  };
+
+  self.resetAppStatus = function (app) {
+    app.isRunning(false);
+    app.status("");
+  };
+
+  self.appendToHistory = function (app) {
+    var newApp = {
+      id:app.id,
+      name:app.name,
+      when:moment().format('MM/DD/YYYY, h:mm:ss a'),
+      archive:app.archive,
+      submitUrl:app.submitUrl,
+      watchUrl:app.watchUrl,
+      killUrl:app.killUrl,
+      rerunUrl:app.rerunUrl,
+      description:app.description,
+      isRunning:ko.observable(app.isRunning()),
+      status:ko.observable(app.status()),
+      progress:ko.observable(app.progress()),
+      progressCss:ko.observable(app.progressCss()),
+      intervalId:app.intervalId,
+      actions:ko.observableArray(app.actions()),
+      output:ko.observable(app.output())
+    };
+    var history = self.history();
+    history.push(newApp);
+    self.history(history);
+  };
+
+};