Browse Source

HUE-2925 [fb] Allow to use absolute URI

Ivan Orlov 10 years ago
parent
commit
bff291a

+ 3 - 3
apps/filebrowser/src/filebrowser/forms.py

@@ -21,12 +21,11 @@ import urllib
 from django import forms
 from django import forms
 from django.contrib.auth.models import User, Group
 from django.contrib.auth.models import User, Group
 from django.forms import FileField, CharField, BooleanField, Textarea
 from django.forms import FileField, CharField, BooleanField, Textarea
-from django.forms.formsets import formset_factory, BaseFormSet, ManagementForm
+from django.forms.formsets import formset_factory, BaseFormSet
 
 
 from desktop.lib import i18n
 from desktop.lib import i18n
+from desktop.lib.fs.utils import normpath
 from filebrowser.lib import rwx
 from filebrowser.lib import rwx
-from hadoop.fs import normpath
-
 
 
 from django.utils.translation import ugettext_lazy as _
 from django.utils.translation import ugettext_lazy as _
 
 
@@ -63,6 +62,7 @@ class PathField(CharField):
   def clean(self, value):
   def clean(self, value):
     return normpath(CharField.clean(self, value))
     return normpath(CharField.clean(self, value))
 
 
+
 class EditorForm(forms.Form):
 class EditorForm(forms.Form):
   path = PathField(label=_("File to edit"))
   path = PathField(label=_("File to edit"))
   contents = CharField(widget=Textarea, label=_("Contents"), required=False)
   contents = CharField(widget=Textarea, label=_("Contents"), required=False)

+ 12 - 7
apps/filebrowser/src/filebrowser/templates/fb_components.mako

@@ -26,8 +26,8 @@ from django.utils.translation import ugettext as _
         <li>
         <li>
             <span style="float:right; margin-top:10px;"><i id="editBreadcrumb" class="fa fa-pencil hand" rel="tooltip" title="${_('Edit path')}"></i></span>
             <span style="float:right; margin-top:10px;"><i id="editBreadcrumb" class="fa fa-pencil hand" rel="tooltip" title="${_('Edit path')}"></i></span>
             <ul class="hueBreadcrumb" data-bind="foreach: breadcrumbs" style="padding-right:40px; padding-top: 12px">
             <ul class="hueBreadcrumb" data-bind="foreach: breadcrumbs" style="padding-right:40px; padding-top: 12px">
-                <li data-bind="visible: label == '/'"><a href="#" data-bind="click: show"><span class="divider" data-bind="text: label"></span></a></li>
-                <li data-bind="visible: label != '/'"><a href="#" data-bind="text: label, click: show"></a><span class="divider">/</span></li>
+                <li data-bind="visible: label.slice(-1) == '/'"><a href="#" data-bind="click: show"><span class="divider" data-bind="text: label"></span></a></li>
+                <li data-bind="visible: label.slice(-1) != '/'"><a href="#" data-bind="text: label, click: show"></a><span class="divider">/</span></li>
             </ul>
             </ul>
             <input id="hueBreadcrumbText" type="text" class="input-xxlarge" style="margin-top:4px;margin-right:4px;display:none" data-bind="value: currentPath" autocomplete="off" />
             <input id="hueBreadcrumbText" type="text" class="input-xxlarge" style="margin-top:4px;margin-right:4px;display:none" data-bind="value: currentPath" autocomplete="off" />
         </li>
         </li>
@@ -48,12 +48,17 @@ from django.utils.translation import ugettext as _
         <li>
         <li>
             <ul class="hueBreadcrumb" style="padding-right:40px; padding-top: 12px">
             <ul class="hueBreadcrumb" style="padding-right:40px; padding-top: 12px">
                     % for breadcrumb_item in breadcrumbs:
                     % for breadcrumb_item in breadcrumbs:
-                    <% label = breadcrumb_item['label'] %>
-                    %if label == '/':
-                            <li><a href="/filebrowser/view=${breadcrumb_item['url']}"><span
-                                    class="divider">${label}</span></a></li>
+                    <% label, f_url = breadcrumb_item['label'], breadcrumb_item['url'] %>
+                    %if label[-1] == '/':
+                            <li>
+                              <a href="${url('filebrowser.views.view', path=f_url)}">
+                                <span class="divider">${label}</span>
+                              </a>
+                            </li>
                     %else:
                     %else:
-                            <li><a href="/filebrowser/view=${breadcrumb_item['url']}">${label}</a><span class="divider">/</span></li>
+                            <li>
+                              <a href="${url('filebrowser.views.view', path=f_url)}">${label}</a>
+                              <span class="divider">/</span></li>
                     %endif
                     %endif
                     % endfor
                     % endfor
             </ul>
             </ul>

+ 20 - 20
apps/filebrowser/src/filebrowser/templates/listdir_components.mako

@@ -602,7 +602,7 @@ from django.utils.translation import ugettext as _
       $('.history').removeClass('no-history');
       $('.history').removeClass('no-history');
       var history = getHistory();
       var history = getHistory();
       if (path != '/filebrowser/') {
       if (path != '/filebrowser/') {
-        var _basePath = '${url('filebrowser.views.view', path=urlencode('/'))}';
+        var _basePath = '${url('filebrowser.views.view', path='')}';
         if (path.indexOf(_basePath) > -1) {
         if (path.indexOf(_basePath) > -1) {
           path = path.substr(_basePath.length - 1);
           path = path.substr(_basePath.length - 1);
         }
         }
@@ -748,7 +748,7 @@ from django.utils.translation import ugettext as _
           }
           }
 
 
           viewModel.targetPageNum(1);
           viewModel.targetPageNum(1);
-          viewModel.targetPath("${url('filebrowser.views.view', path=urlencode('/'))}" + stripHashes(this.url));
+          viewModel.targetPath("${url('filebrowser.views.view', path='')}" + stripHashes(this.url));
           location.hash = this.url;
           location.hash = this.url;
         }
         }
       }
       }
@@ -998,7 +998,7 @@ from django.utils.translation import ugettext as _
           // Reset page number so that we don't hit a page that doesn't exist
           // Reset page number so that we don't hit a page that doesn't exist
           self.targetPageNum(1);
           self.targetPageNum(1);
           self.searchQuery("");
           self.searchQuery("");
-          self.targetPath("${url('filebrowser.views.view', path=urlencode('/'))}" + "." + stripHashes(file.path));
+          self.targetPath("${url('filebrowser.views.view', path='')}" + stripHashes(file.path));
           location.hash = stripHashes(file.path);
           location.hash = stripHashes(file.path);
         } else {
         } else {
           location.href = file.url;
           location.href = file.url;
@@ -1006,11 +1006,11 @@ from django.utils.translation import ugettext as _
       };
       };
 
 
       self.editFile = function () {
       self.editFile = function () {
-        location.href = "${url('filebrowser.views.edit', path=urlencode('/'))}" + self.selectedFile().path;
+        location.href = "${url('filebrowser.views.edit', path='')}" + self.selectedFile().path;
       };
       };
 
 
       self.downloadFile = function () {
       self.downloadFile = function () {
-        location.href = "${url('filebrowser.views.download', path=urlencode('/'))}" + self.selectedFile().path;
+        location.href = "${url('filebrowser.views.download', path='')}" + self.selectedFile().path;
       };
       };
 
 
       self.renameFile = function () {
       self.renameFile = function () {
@@ -1020,7 +1020,7 @@ from django.utils.translation import ugettext as _
 
 
         $("#newNameInput").val(self.selectedFile().name);
         $("#newNameInput").val(self.selectedFile().name);
 
 
-        $("#renameForm").attr("action", "/filebrowser/rename?next=${url('filebrowser.views.view', path=urlencode('/'))}" + "." + self.currentPath());
+        $("#renameForm").attr("action", "/filebrowser/rename?next=${url('filebrowser.views.view', path='')}" + self.currentPath());
 
 
         $("#renameModal").modal({
         $("#renameModal").modal({
           keyboard:true,
           keyboard:true,
@@ -1042,7 +1042,7 @@ from django.utils.translation import ugettext as _
         if (!isMoveOnSelf){
         if (!isMoveOnSelf){
           hiddenFields($("#moveForm"), "src_path", paths);
           hiddenFields($("#moveForm"), "src_path", paths);
 
 
-          $("#moveForm").attr("action", "/filebrowser/move?next=${url('filebrowser.views.view', path=urlencode('/'))}" + "." + self.currentPath());
+          $("#moveForm").attr("action", "/filebrowser/move?next=${url('filebrowser.views.view', path='')}" + self.currentPath());
 
 
           if (mode === 'nomodal') {
           if (mode === 'nomodal') {
             $.jHueNotify.info('${ _('Items moving to') } "' + $('#moveDestination').val() + '"');
             $.jHueNotify.info('${ _('Items moving to') } "' + $('#moveDestination').val() + '"');
@@ -1082,7 +1082,7 @@ from django.utils.translation import ugettext as _
 
 
         hiddenFields($("#copyForm"), "src_path", paths);
         hiddenFields($("#copyForm"), "src_path", paths);
 
 
-        $("#copyForm").attr("action", "/filebrowser/copy?next=${url('filebrowser.views.view', path=urlencode('/'))}" + "." + self.currentPath());
+        $("#copyForm").attr("action", "/filebrowser/copy?next=${url('filebrowser.views.view', path='')}" + self.currentPath());
 
 
         $("#copyModal").modal({
         $("#copyModal").modal({
           keyboard:true,
           keyboard:true,
@@ -1116,7 +1116,7 @@ from django.utils.translation import ugettext as _
 
 
           hiddenFields($("#chownForm"), 'path', paths);
           hiddenFields($("#chownForm"), 'path', paths);
 
 
-          $("#chownForm").attr("action", "/filebrowser/chown?next=${url('filebrowser.views.view', path=urlencode('/'))}" + "." + self.currentPath());
+          $("#chownForm").attr("action", "/filebrowser/chown?next=${url('filebrowser.views.view', path='')}" + self.currentPath());
 
 
           $("select[name=user]").val(self.selectedFile().stats.user);
           $("select[name=user]").val(self.selectedFile().stats.user);
 
 
@@ -1153,7 +1153,7 @@ from django.utils.translation import ugettext as _
 
 
           hiddenFields($("#chmodForm"), 'path', paths);
           hiddenFields($("#chmodForm"), 'path', paths);
 
 
-          $("#chmodForm").attr("action", "/filebrowser/chmod?next=${url('filebrowser.views.view', path=urlencode('/'))}" + "." + self.currentPath());
+          $("#chmodForm").attr("action", "/filebrowser/chmod?next=${url('filebrowser.views.view', path='')}" + self.currentPath());
 
 
           $("#changePermissionModal").modal({
           $("#changePermissionModal").modal({
             keyboard: true,
             keyboard: true,
@@ -1196,7 +1196,7 @@ from django.utils.translation import ugettext as _
 
 
         $("#deleteForm").attr("action", "/filebrowser/rmtree" + "?" +
         $("#deleteForm").attr("action", "/filebrowser/rmtree" + "?" +
           (skip_trash ? "skip_trash=true&" : "") +
           (skip_trash ? "skip_trash=true&" : "") +
-          "next=${url('filebrowser.views.view', path=urlencode('/'))}" + "." + self.currentPath());
+          "next=${url('filebrowser.views.view', path='')}" + self.currentPath());
 
 
         $("#deleteModal").modal({
         $("#deleteModal").modal({
           keyboard:true,
           keyboard:true,
@@ -1224,12 +1224,12 @@ from django.utils.translation import ugettext as _
       };
       };
 
 
       self.createDirectory = function (formElement) {
       self.createDirectory = function (formElement) {
-        $(formElement).attr("action", "/filebrowser/mkdir?next=${url('filebrowser.views.view', path=urlencode('/'))}" + "." + self.currentPath());
+        $(formElement).attr("action", "/filebrowser/mkdir?next=${url('filebrowser.views.view', path='')}" + self.currentPath());
         return true;
         return true;
       };
       };
 
 
       self.createFile = function (formElement) {
       self.createFile = function (formElement) {
-        $(formElement).attr("action", "/filebrowser/touch?next=${url('filebrowser.views.view', path=urlencode('/'))}" + "." + self.currentPath());
+        $(formElement).attr("action", "/filebrowser/touch?next=${url('filebrowser.views.view', path='')}" + self.currentPath());
         return true;
         return true;
       };
       };
 
 
@@ -1242,7 +1242,7 @@ from django.utils.translation import ugettext as _
 
 
         hiddenFields($("#restoreTrashForm"), 'path', paths);
         hiddenFields($("#restoreTrashForm"), 'path', paths);
 
 
-        $("#restoreTrashForm").attr("action", "/filebrowser/trash/restore?next=${url('filebrowser.views.view', path=urlencode('/'))}" + "." + self.currentPath());
+        $("#restoreTrashForm").attr("action", "/filebrowser/trash/restore?next=${url('filebrowser.views.view', path='')}" + self.currentPath());
 
 
         $("#restoreTrashModal").modal({
         $("#restoreTrashModal").modal({
           keyboard:true,
           keyboard:true,
@@ -1259,7 +1259,7 @@ from django.utils.translation import ugettext as _
 
 
         hiddenFields($("#purgeTrashForm"), 'path', paths);
         hiddenFields($("#purgeTrashForm"), 'path', paths);
 
 
-        $("#purgeTrashForm").attr("action", "/filebrowser/trash/purge?next=${url('filebrowser.views.view', path=urlencode('/'))}" + viewModel.homeDir().slice(1) + "/.Trash");
+        $("#purgeTrashForm").attr("action", "/filebrowser/trash/purge?next=${url('filebrowser.views.view', path='')}" + viewModel.homeDir() + "/.Trash");
 
 
         $("#purgeTrashModal").modal({
         $("#purgeTrashModal").modal({
           keyboard:true,
           keyboard:true,
@@ -1783,9 +1783,9 @@ from django.utils.translation import ugettext as _
         var targetPath = "";
         var targetPath = "";
         var hash = window.location.hash.substring(1).replace(/(<([^>]+)>)/ig, "");
         var hash = window.location.hash.substring(1).replace(/(<([^>]+)>)/ig, "");
         if (hash != null && hash != "") {
         if (hash != null && hash != "") {
-          targetPath = "${url('filebrowser.views.view', path=urlencode('/'))}";
+          targetPath = "${url('filebrowser.views.view', path='')}";
           if (hash.indexOf("!!") != 0) {
           if (hash.indexOf("!!") != 0) {
-            targetPath += stripHashes(hash.substring(1));
+            targetPath += stripHashes(hash);
           }
           }
           else {
           else {
             targetPath = viewModel.targetPath() + hash;
             targetPath = viewModel.targetPath() + hash;
@@ -1825,7 +1825,7 @@ from django.utils.translation import ugettext as _
         home: "/user/${ user }/",
         home: "/user/${ user }/",
         skipKeydownEvents: true,
         skipKeydownEvents: true,
         onEnter: function (el) {
         onEnter: function (el) {
-          viewModel.targetPath("${url('filebrowser.views.view', path=urlencode('/'))}" + stripHashes(el.val().substring(1)));
+          viewModel.targetPath("${url('filebrowser.views.view', path='')}" + stripHashes(el.val()));
           viewModel.getStats(function (data) {
           viewModel.getStats(function (data) {
             if (data.type != null && data.type == "file") {
             if (data.type != null && data.type == "file") {
               location.href = data.url;
               location.href = data.url;
@@ -1860,9 +1860,9 @@ from django.utils.translation import ugettext as _
         if (hash != null && hash != "") {
         if (hash != null && hash != "") {
           addPathToHistory(hash);
           addPathToHistory(hash);
 
 
-          targetPath = "${url('filebrowser.views.view', path=urlencode('/'))}";
+          targetPath = "${url('filebrowser.views.view', path='')}";
           if (hash.indexOf("!!") != 0) {
           if (hash.indexOf("!!") != 0) {
-            targetPath += stripHashes(hash.substring(1));
+            targetPath += stripHashes(hash);
           }
           }
           else {
           else {
             targetPath = viewModel.targetPath() + hash;
             targetPath = viewModel.targetPath() + hash;

+ 18 - 20
apps/filebrowser/src/filebrowser/views.py

@@ -31,7 +31,6 @@ from datetime import datetime
 
 
 from django.contrib import messages
 from django.contrib import messages
 from django.contrib.auth.models import User, Group
 from django.contrib.auth.models import User, Group
-from django.core import urlresolvers
 from django.core.urlresolvers import reverse
 from django.core.urlresolvers import reverse
 from django.template.defaultfilters import stringformat, filesizeformat
 from django.template.defaultfilters import stringformat, filesizeformat
 from django.http import Http404, HttpResponse, HttpResponseNotModified
 from django.http import Http404, HttpResponse, HttpResponseNotModified
@@ -50,12 +49,13 @@ from avro import datafile, io
 from desktop import appmanager
 from desktop import appmanager
 from desktop.lib import i18n, paginator
 from desktop.lib import i18n, paginator
 from desktop.lib.conf import coerce_bool
 from desktop.lib.conf import coerce_bool
-from desktop.lib.django_util import make_absolute, render, render_json, format_preserving_redirect
+from desktop.lib.django_util import make_absolute, render, format_preserving_redirect
 from desktop.lib.django_util import JsonResponse
 from desktop.lib.django_util import JsonResponse
 from desktop.lib.exceptions_renderable import PopupException
 from desktop.lib.exceptions_renderable import PopupException
+from desktop.lib.fs import splitpath
 from hadoop.fs.hadoopfs import Hdfs
 from hadoop.fs.hadoopfs import Hdfs
 from hadoop.fs.exceptions import WebHdfsException
 from hadoop.fs.exceptions import WebHdfsException
-from hadoop.fs.fsutils import do_newfile_save, do_overwrite_save
+from hadoop.fs.fsutils import do_overwrite_save
 
 
 from filebrowser.conf import MAX_SNAPPY_DECOMPRESSION_SIZE
 from filebrowser.conf import MAX_SNAPPY_DECOMPRESSION_SIZE
 from filebrowser.conf import SHOW_DOWNLOAD_BUTTON
 from filebrowser.conf import SHOW_DOWNLOAD_BUTTON
@@ -262,14 +262,13 @@ def save_file(request):
     if not is_valid:
     if not is_valid:
         return edit(request, path, form=form)
         return edit(request, path, form=form)
 
 
+    encoding = form.cleaned_data['encoding']
+    data = form.cleaned_data['contents'].encode(encoding)
+
     if request.fs.exists(path):
     if request.fs.exists(path):
-        do_overwrite_save(request.fs, path,
-                           form.cleaned_data['contents'],
-                           form.cleaned_data['encoding'])
+        do_overwrite_save(request.fs, path, data)
     else:
     else:
-        do_newfile_save(request.fs, path,
-                         form.cleaned_data['contents'],
-                         form.cleaned_data['encoding'])
+        request.fs.create(path, overwrite=False, data=data)
 
 
     messages.info(request, _('Saved %(path)s.') % {'path': os.path.basename(path)})
     messages.info(request, _('Saved %(path)s.') % {'path': os.path.basename(path)})
     request.path = reverse("filebrowser.views.edit", kwargs=dict(path=path))
     request.path = reverse("filebrowser.views.edit", kwargs=dict(path=path))
@@ -277,14 +276,13 @@ def save_file(request):
 
 
 
 
 def parse_breadcrumbs(path):
 def parse_breadcrumbs(path):
-    breadcrumbs_parts = Hdfs.normpath(path).split('/')
-    i = 1
-    breadcrumbs = [{'url': '', 'label': '/'}]
-    while (i < len(breadcrumbs_parts)):
-        breadcrumb_url = breadcrumbs[i - 1]['url'] + '/' + breadcrumbs_parts[i]
-        if breadcrumb_url != '/':
-            breadcrumbs.append({'url': breadcrumb_url, 'label': breadcrumbs_parts[i]})
-        i = i + 1
+    parts = splitpath(path)
+    url, breadcrumbs = '', []
+    for part in parts:
+      if url and not url.endswith('/'):
+        url += '/'
+      url += part
+      breadcrumbs.append({'url': url, 'label': part})
     return breadcrumbs
     return breadcrumbs
 
 
 
 
@@ -327,7 +325,7 @@ def listdir(request, path, chooser):
     stats = request.fs.listdir_stats(path)
     stats = request.fs.listdir_stats(path)
 
 
     # Include parent dir, unless at filesystem root.
     # Include parent dir, unless at filesystem root.
-    if Hdfs.normpath(path) != posixpath.sep:
+    if not request.fs.isroot(path):
         parent_path = request.fs.join(path, "..")
         parent_path = request.fs.join(path, "..")
         parent_stat = request.fs.stats(parent_path)
         parent_stat = request.fs.stats(parent_path)
         # The 'path' field would be absolute, but we want its basename to be
         # The 'path' field would be absolute, but we want its basename to be
@@ -411,7 +409,7 @@ def listdir_paged(request, path):
     shown_stats = page.object_list
     shown_stats = page.object_list
 
 
     # Include parent dir always as second option, unless at filesystem root.
     # Include parent dir always as second option, unless at filesystem root.
-    if Hdfs.normpath(path) != posixpath.sep:
+    if not request.fs.isroot(path):
         parent_path = request.fs.join(path, "..")
         parent_path = request.fs.join(path, "..")
         parent_stat = request.fs.stats(parent_path)
         parent_stat = request.fs.stats(parent_path)
         # The 'path' field would be absolute, but we want its basename to be
         # The 'path' field would be absolute, but we want its basename to be
@@ -483,7 +481,7 @@ def _massage_stats(request, stats):
     into the format that the views would like it in.
     into the format that the views would like it in.
     """
     """
     path = stats['path']
     path = stats['path']
-    normalized = Hdfs.normpath(path)
+    normalized = request.fs.normpath(path)
     return {
     return {
         'path': normalized,
         'path': normalized,
         'name': stats['name'],
         'name': stats['name'],

+ 15 - 0
desktop/core/src/desktop/lib/fs/__init__.py

@@ -16,6 +16,21 @@
 
 
 from __future__ import absolute_import
 from __future__ import absolute_import
 
 
+import posixpath
+import urlparse
+
 from desktop.lib.fs.proxyfs import ProxyFS
 from desktop.lib.fs.proxyfs import ProxyFS
 
 
 
 
+def splitpath(path):
+  split = urlparse.urlparse(path)
+  if split.scheme:
+    parts = [split.scheme + '://', split.netloc] + split.path.split('/')
+  else:
+    parts = ['/'] + posixpath.normpath(path).split('/')
+  # Filter empty parts out
+  return filter(len, parts)
+
+
+
+

+ 36 - 0
desktop/core/src/desktop/lib/fs/fs_test.py

@@ -0,0 +1,36 @@
+# 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 __future__ import absolute_import
+
+from nose.tools import eq_
+
+from desktop.lib import fs
+
+
+def test_splitpath():
+  s = fs.splitpath
+
+  eq_(s('s3://'), ['s3://'])
+  eq_(s('s3://bucket'), ['s3://', 'bucket'])
+  eq_(s('s3://bucket/key'), ['s3://', 'bucket', 'key'])
+  eq_(s('s3://bucket/key/'), ['s3://', 'bucket', 'key'])
+  eq_(s('s3://bucket/bar/foo'), ['s3://', 'bucket', 'bar', 'foo'])
+
+  eq_(s('/'), ['/'])
+  eq_(s('/dir'), ['/', 'dir'])
+  eq_(s('/dir/file'), ['/', 'dir', 'file'])
+  eq_(s('/dir/file/'), ['/', 'dir', 'file'])

+ 9 - 11
desktop/core/src/desktop/static/desktop/js/jquery.hdfsautocomplete.js

@@ -211,18 +211,16 @@
     var BASE_PATH = "/filebrowser/view=";
     var BASE_PATH = "/filebrowser/view=";
     var _currentFiles = [];
     var _currentFiles = [];
 
 
+    function prepareAutocompletePath(path) {
+      if (path.indexOf('/') == 0 || /^([a-zA-Z0-9]+):\/\//.test(path))
+        return path.substr(0, path.lastIndexOf("/") + 1);
+      if (path.indexOf("/") > 0)
+        return _this.options.home + path.substr(0, path.lastIndexOf("/"));
+      return _this.options.home;
+    }
+
     function showHdfsAutocomplete(callback) {
     function showHdfsAutocomplete(callback) {
-      var path = _el.val();
-      var autocompleteUrl = BASE_PATH;
-      if (path.indexOf("/") == 0) {
-        autocompleteUrl += path.substr(0, path.lastIndexOf("/"));
-      }
-      else if (path.indexOf("/") > 0) {
-        autocompleteUrl += _this.options.home + path.substr(0, path.lastIndexOf("/"));
-      }
-      else {
-        autocompleteUrl += _this.options.home;
-      }
+      autocompleteUrl = BASE_PATH + prepareAutocompletePath(_el.val());
       $.getJSON(autocompleteUrl + "?pagesize=1000&format=json", function (data) {
       $.getJSON(autocompleteUrl + "?pagesize=1000&format=json", function (data) {
         _currentFiles = [];
         _currentFiles = [];
         if (data.error == null) {
         if (data.error == null) {

+ 5 - 21
desktop/libs/hadoop/src/hadoop/fs/fsutils.py

@@ -23,21 +23,17 @@ import stat as stat_module
 logger = logging.getLogger(__name__)
 logger = logging.getLogger(__name__)
 
 
 
 
-def do_overwrite_save(fs, path, data, encoding):
+def do_overwrite_save(fs, path, data):
 
 
     def copy_data(path_dest):
     def copy_data(path_dest):
-        new_file = fs.open(path_dest, "w")
         try:
         try:
-            try:
-                new_file.write(data.encode(encoding))
-                logging.info("Wrote to " + path_dest)
-            finally:
-                new_file.close()
+            fs.create(path_dest, overwrite=False, data=data)
+            logging.info("Wrote to " + path_dest)
         except Exception, e:
         except Exception, e:
             # An error occurred in writing, we should clean up
             # An error occurred in writing, we should clean up
             # the tmp file if it exists, before re-raising
             # the tmp file if it exists, before re-raising
             try:
             try:
-                fs.remove(path_dest)
+                fs.remove(path_dest, skip_trash=True)
             except:
             except:
                 logger.exception('failed to remove %s' % path_dest)
                 logger.exception('failed to remove %s' % path_dest)
             raise e
             raise e
@@ -84,7 +80,7 @@ def _do_overwrite(fs, path, copy_data):
         # but not the end of the world - keep going
         # but not the end of the world - keep going
 
 
     # Now delete the old - nothing we can do here to recover
     # Now delete the old - nothing we can do here to recover
-    fs.remove(path)
+    fs.remove(path, skip_trash=True)
 
 
     # Now move the new one into place
     # Now move the new one into place
     # If this fails, then we have no reason to assume
     # If this fails, then we have no reason to assume
@@ -93,15 +89,3 @@ def _do_overwrite(fs, path, copy_data):
     fs.rename(path_dest, path)
     fs.rename(path_dest, path)
 
 
 
 
-def do_newfile_save(fs, path, data, encoding):
-    """
-    Save data to the path 'path' on the filesystem 'fs'.
-
-    There must not be a pre-existing file at that path.
-    """
-    new_file = fs.open(path, "w")
-    try:
-        new_file.write(data.encode(encoding))
-    finally:
-        new_file.close()
-

+ 2 - 2
desktop/libs/hadoop/src/hadoop/fs/fsutils_tests.py

@@ -18,7 +18,7 @@
 import logging
 import logging
 import unittest
 import unittest
 
 
-from nose.tools import assert_equals, assert_true, assert_not_equal
+from nose.tools import assert_equals, assert_not_equal
 
 
 from desktop.lib import i18n
 from desktop.lib import i18n
 
 
@@ -60,7 +60,7 @@ curacao\t?"""
     f.close()
     f.close()
 
 
     encoding = i18n.get_site_encoding()
     encoding = i18n.get_site_encoding()
-    do_overwrite_save(fs, path, data, encoding)
+    do_overwrite_save(fs, path, data.encode(encoding))
 
 
     assert_not_equal(data_body, fs.open(path).read())
     assert_not_equal(data_body, fs.open(path).read())