how to rename a folder in Google-storage programmatically? - java

I have a google-storage java client.
I want to rename a folder on the cloud.
It there a way to do it?
I saw the update post but i'm not sure how to change the name meta data.
here is my try but i don't know what to fill in "entity" and there is no oac.setName()
public void renameDirectory(String oldPath, String newName) throws IOException {
final Storage gsClient = GCSlientFactory.get(PromptoConfig.s.GCP_PROJECT_ID).getGSClient();
final URI uri = URI.create(oldPath);
ObjectAccessControl oac = new ObjectAccessControl();
oac.setId("newName");
final Storage.ObjectAccessControls.Update update = gsClient.objectAccessControls().update(BUCKET_NAME, uri.toString().replace("gs://"+BUCKET_NAME+"/", ""), "", oac);
update.execute();
}
and also:
final Storage gsClient = GCSlientFactory.get(PromptoConfig.s.GCP_PROJECT_ID).getGSClient();
final URI uri = URI.create(oldPath);
ObjectAccessControl oac = new ObjectAccessControl();
oac.set("name", newName);
final Storage.ObjectAccessControls.Update update = gsClient.objectAccessControls().update(BUCKET_NAME, uri.toString().replace("gs://"+BUCKET_NAME+"/", ""), "allUsers", oac);
update.execute();

GCS doesn't support true folders -- the namespace is flat, and the meaning of "/" is really imposed by clients (and client libraries). As such, folders can't be renamed atomically - you would need to rename each of the contained files, like what the gsutil mv command does. You can see this by running a command like:
gsutil -d mv gs://my-bucket/folder1 gs://my-bucket/folder2
The -d option will cause it to output the sequence of requests gsutil generates to do the rename.

Related

Does System.IO.File encapsulates SMB1.0/SMB2.0?

I am new to SMB1.0/SMB2.0 and am trying to create a C# class library to encapsulate basic File/Directory operations like Copy, ReadAllText, Delete, etc., using https://github.com/TalAloni/SMBLibrary.
My questions are:
Is System.IO.File already encapsulate SMB1.0/SMB2.0 protocol, and do I not need to use 3rd party SMBLibrary?
I have written the following code to Move a file from one SMB share to another SMB share, but it only renames and does not Move the file from a source location to the target location. How can I do that?
public bool Move(string sourceFilePath, string targetFilePath)
{
if (!CheckLoggedIn())
{
return false;
}
object fileHandle = null;
_status = _store.CreateFile(out fileHandle,
out FileStatus _,
sourceFilePath,
AccessMask.GENERIC_ALL | AccessMask.SYNCHRONIZE,
FileAttributes.Normal,
ShareAccess.Write,
CreateDisposition.FILE_OPEN,
CreateOptions.FILE_NON_DIRECTORY_FILE | CreateOptions.FILE_SYNCHRONOUS_IO_ALERT,
null);
if (_status == NTStatus.STATUS_SUCCESS)
{
_status = _store.SetFileInformation(fileHandle, new FileRenameInformationType2()
{
FileName = targetFilePath
});
_status = _store.CloseFile(fileHandle);
}
return _status == NTStatus.STATUS_SUCCESS;
}
No, System.IO does not contain an SMB 1.0 or SMB 2.0 client.
In order to move file from one share to another, the client must read the content of the file from the source share, and then write its content to the second share. it must be copied in this manner (and then deleted from the source).
I found EzSmb https://github.com/ume05rw/EzSmb library with which you could move files within same SMB share using the following code:
// ** SMB1 NOT Supported. **
//using EzSmb;
//using System;
//using System.Threading.Tasks;
// Get Node of file.
var file = await Node.GetNode(#"192.168.0.1\ShareName\FileName.txt", "userName", "password");
// Move to child folder path.
// ** Even if you don't change the file/folder name, write the name. **
var movedFile = await file.Move(#"FolderName\RenamedFileName.txt");
Console.WriteLine(movedFile.FullPath);
// -> 192.168.0.1\ShareName\FolderName\RenamedFileName.txt
// Get Node of folder.
var folder = await Node.GetNode(#"192.168.0.1\ShareName\FolderName\SubFolderName", "userName", "password");
// Move to Parent path.
var movedFolder = await folder.Move(#"..\RenamedSubFolderName");
Console.WriteLine(movedFolder.FullPath);
// -> 192.168.0.1\ShareName\RenamedSubFolderName

How to get the Git submission information of the current line of the current file

How to get the Git submission information of the current line of the current file, I want to get the author's username
I have got the current file and the current line number.
#Override
public void actionPerformed(AnActionEvent e) {
final Editor editor = e.getRequiredData(CommonDataKeys.EDITOR);
final Document document = editor.getDocument();
FileDocumentManager fileDocumentManager = FileDocumentManager.getInstance();
VirtualFile currentFile = fileDocumentManager.getFile(document);
if (e.getProject() == null || currentFile == null) {
return;
}
final PsiFile psiFile = PsiManager.getInstance(e.getProject()).findFile(currentFile);
String path = psiFile.getVirtualFile().getPath();
path = path.replace(e.getProject().getBasePath(), "");
BookMarkXPersistentStateComponent service = BookMarkXPersistentStateComponent.getInstance();
String projectName = e.getProject().getName();
int currentLineNumber = editor.getCaretModel().getLogicalPosition().line;
service.addBookMark(new BookmarkXItemState(projectName, path, currentLineNumber, new Date()));
}
If I understand the question correctly, you are looking for the annotations (blame) info.
If you need this info for a single line only, you could get it directly from git by running a custom git command like git log -n 1 -L <line-number>,<line-number>:<path-to-file>. See git-log help for details.
To run this command, use GitHandler class.
You could also use builtin Annotations feature of IntelliJ to get this information, however this will require loading annotations of the entire file first. To go this way, check com.intellij.openapi.vcs.annotate.AnnotationProvider
After annotating a file via provder you can use com.intellij.openapi.vcs.annotate.FileAnnotation.CurrentFileRevisionProvider#getRevision, from which you can get com.intellij.openapi.vcs.history.VcsFileRevision#getAuthor
Also, take a look at https://intellij-support.jetbrains.com/hc/en-us/community/posts/360004109859--VcsUtil-getVcsFor-return-null

Is there a clean and easy way to make file path strings in Java OS agnostic?

I've made a class which takes in any string of one format (eg. UNIX) and coverts into whatever OS the java is running on.
enum OperatingSystem {
WINDOWS,
LINUX;
static OperatingSystem initOS() {
String osName = System.getProperty("os.name");
switch (osName) {
case "Windows 8.1":
return WINDOWS;
case "Linux":
return LINUX;
default:
return LINUX;
}
}
}
public class OSSP {
public static final OperatingSystem USEROS = OperatingSystem.initOS();
// Auxilarry methods to return OSAppropriateString
private static String makeLinuxCompatible(String[] path) {
return String.join("/", path);
}
private static String makeWindowsCompatible(String[] path) {
return String.join("\\", path);
}
public static String getOSSpecificPath(String path) {
String[] splittedPath = {""}, subpath = {""};
String finalPath = "";
if(path.contains("\\")) {
splittedPath = path.split("\\\\",-1);
}
else if (path.contains("/")) {
splittedPath = path.split("/",-1);
}
if (USEROS == OperatingSystem.LINUX) {
finalPath = makeLinuxCompatible(splittedPath);
}
else if (USEROS == OperatingSystem.WINDOWS) {
finalPath = makeWindowsCompatible(splittedPath);
}
return finalPath;
}
}
This is fine if you're working on small code and you'd have to do it often.
But, I have a huge GUI code where I'd have to insert this function wherever there is path specified in the program. Is there a way to make path like strings automatically OS specific?
Otherwise a setting where any OS function which takes a path automatically changes accordingly under the hood.
Use Path with Files.
Path path = Paths.get(".../...");
Path path = Paths.get("...", "...");
// path.resolve, relativize, normalize, getFileSystem
This class is a generalisation of File which is only for pure file system files.
A path might point in a subdirectory of a .zip using a zip file system and so on.
For established File using APIs one can use Path.toFile() and File.toPath().
Paths.get is very versatile, also due to the Posix compatibility of Windows (accepting / besides \). You can get a canonical normalized path anyway.
path.toRealPath()
The old File you can use:
String separator = File.separator;
For a path which can point to different file systems:
String separator = path.getFileSystem().getSeparator();
In general Path is a nifty class storing the name parts, the file system.
It covers many aspects like "..".
The best way to deal with this kind of situation is to not try to detect the OS since that can be rather hit-or-miss. Instead the Java API does provide a way to tell you what character to use as a path separator. Look at this API documentation on File: https://docs.oracle.com/javase/8/docs/api/java/io/File.html and look for the specific static field separator. I would highly suggest you parse the path using the File class then if you need the path as an string simply call toURI().toString() to get it into a format that the OS can recognize.

How to retrieve the UNC path instead of mapped drive path from JFileChooser

Just wondering if there is a way to return back the UNC path from a file chosen with JFileChooser. The file that I would be selecting would reside on a mapped drive that has a UNC path. Right now, I can only seem to pull back the drive letter of a mapped drive.
From https://stackoverflow.com/users/715934/tasoocoo
I ended up finding a solution that executes the NET USE command:
filePath = fc.getSelectedFile().getAbsolutePath();
Runtime runTime = Runtime.getRuntime();
Process process = runTime.exec("net use");
InputStream inStream = process.getInputStream();
InputStreamReader inputStreamReader = new InputStreamReader(inStream);
BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
String line = null;
String[] components = null;
while (null != (line = bufferedReader.readLine())) {
components = line.split("\\s+");
if ((components.length > 2) && (components[1].equals(filePath.substring(0, 2)))) {
filePath = filePath.replace(components[1], components[2]);
}
}
As I commented on Gerry's answer, ShellFolder.getDisplayName is unreliable because the user can changed the display name to whatever they want.
However the UNC path does seem to be available via sun.awt.shell.ShellFolder. This is of course an "internal proprietary API" so no guarantee this will continue to work in future versions of java, but testing against java 1.8.0_31 in Windows 7 I see a ShellFolderColumnInfo titled Attributes which for network drives appears to include the UNC path as a bare String. eg:
File networkDrive = new File("G:\");
ShellFolder shellFolder = ShellFolder.getShellFolder(networkDrive);
ShellFolderColumnInfo[] cols = shellFolder.getFolderColumns();
for (int i = 0; i < cols.length; i++) {
if ("Attributes".equals(cols[i].getTitle())) {
String uncPath = (String) shellFolder.getFolderColumnValue(i);
System.err.println(uncPath);
break; // don't need to look at other columns
}
}
If you go to My Computer in explorer, change to Details view and turn on the "Network Location" column, it appears to match what we get from "Attributes" via the ShellFolder API. Not sure where "Attributes" comes from or if it changes in non-english locales.
The JFileChooser method getSelectedFile() returns a File, which may have helpful information.
"For Microsoft Windows platforms,…the prefix of a UNC pathname is "\\\\"; the hostname and the share name are the first two names in the name sequence."
If anyone else is looking for an alternate (and I think simpler) solution,
you can find the information using ShellFolder.getDisplayName(). For example, you can parse the network location of the drive from the string here:
System.out.println(ShellFolder.getShellFolder(new File(filePath.substring(0,3))).getDisplayName());
This might also be useful:
File.listRoots();

Generating a canonical path

Does any one know of any Java libraries I could use to generate canonical paths (basically remove back-references).
I need something that will do the following:
Raw Path -> Canonical Path
/../foo/ -> /foo
/foo/ -> /foo
/../../../ -> /
/./foo/./ -> /foo
//foo//bar -> /foo/bar
//foo/../bar -> /bar
etc...
At the moment I lazily rely on using:
new File("/", path).getCanonicalPath();
But this resolves the path against the actual file system, and is synchronised.
java.lang.Thread.State: BLOCKED (on object monitor)
at java.io.ExpiringCache.get(ExpiringCache.java:55)
- waiting to lock <0x93a0d180> (a java.io.ExpiringCache)
at java.io.UnixFileSystem.canonicalize(UnixFileSystem.java:137)
at java.io.File.getCanonicalPath(File.java:559)
The paths that I am canonicalising do not exist on my file system, so just the logic of the method will do me fine, thus not requiring any synchronisation. I'm hoping for a well tested library rather than having to write my own.
I think you can use the URI class to do this; e.g. if the path contains no characters that need escaping in a URI path component, you can do this.
String normalized = new URI(path).normalize().getPath();
If the path contains (or might contain) characters that need escaping, the multi-argument constructors will escape the path argument, and you can provide null for the other arguments.
Notes:
The above normalizes a file path by treating it as a relative URI. If you want to normalize an entire URI ... including the (optional) scheme, authority, and other components, don't call getPath()!
URI normalization does not involve looking at the file system as File canonicalization does. But the flip side is that normalization behaves differently to canonicalization when there are symbolic links in the path.
Using Apache Commons IO (a well-known and well-tested library)
public static String normalize(String filename)
will do exactly what you're looking for.
Example:
String result = FilenameUtils.normalize(myFile.getAbsolutePath());
If you don't need path canonization but only normalization, in Java 7 you can use java.nio.file.Path.normalize method.
According to http://docs.oracle.com/javase/7/docs/api/java/nio/file/Path.html:
This method does not access the file system; the path may not locate a file that exists.
If you work with File object you can use something like this:
file.toPath().normalize().toFile()
You could try an algorithm like this:
String collapsePath(String path) {
/* Split into directory parts */
String[] directories = path.split("/");
String[] newDirectories = new String[directories.length];
int i, j = 0;
for (i=0; i<directories.length; i++) {
/* Ignore the previous directory if it is a double dot */
if (directories[i].equals("..") && j > 0)
newDirectories[j--] = "";
/* Completely ignore single dots */
else if (! directories[i].equals("."))
newDirectories[j++] = directories[i];
}
/* Ah, what I would give for String.join() */
String newPath = new String();
for (i=0; i < j; i++)
newPath = newPath + "/" + newDirectories[i];
return newPath;
}
It isn't perfect; it's linear over the number of directories but does make a copy in memory.
Which kind of path is qualified as a Canonical Path is OS dependent.
That's why Java need to check it on the filesystem.
So there's no simple logic to test the path without knowing the OS.
So, while normalizing can do the trick, here is a procedure that exposes a little more of the Java API than would simply calling Paths.normalize()
Say I want to find a file that is not in my current directory on the file system.
My working code file is
myproject/src/JavaCode.java
Located in myproject/src/. My file is in
../../data/myfile.txt
I'm testing my program running my code from JavaCode.java
public static void main(String[] args) {
findFile("../../data","myfile.txt");
System.out.println("Found it.");
}
public static File findFile(String inputPath, String inputFile) {
File dataDir = new File("").getAbsoluteFile(); // points dataDir to working directory
String delimiters = "" + '\\' + '/'; // dealing with different system separators
StringTokenizer st = new StringTokenizer(inputPath, delimiters);
while(st.hasMoreTokens()) {
String s = st.nextToken();
if(s.trim().isEmpty() || s.equals("."))
continue;
else if(s.equals(".."))
dataDir = dataDir.getParentFile();
else {
dataDir = new File(dataDir, s);
if(!dataDir.exists())
throw new RuntimeException("Data folder does not exist.");
}
}
return new File(dataDir, inputFile);
}
Having placed a file at the specified location, this should print "Found it."
I'm assuming you have strings and you want strings, and you have Java 7 available now, and your default file system uses '/' as a path separator, so try:
String output = FileSystems.getDefault().getPath(input).normalize().toString();
You can try this out with:
/**
* Input Output
* /../foo/ -> /foo
* /foo/ -> /foo
* /../../../ -> /
* /./foo/./ -> /foo
* //foo//bar -> /foo/bar
* //foo/../bar -> /bar
*/
#Test
public void testNormalizedPath() throws URISyntaxException, IOException {
String[] in = new String[]{"/../foo/", "/foo/", "/../../../", "/./foo/./",
"//foo/bar", "//foo/../bar", "/", "/foo"};
String[] ex = new String[]{"/foo", "/foo", "/", "/foo", "/foo/bar", "/bar", "/", "/foo"};
FileSystem fs = FileSystems.getDefault();
for (int i = 0; i < in.length; i++) {
assertEquals(ex[i], fs.getPath(in[i]).normalize().toString());
}
}

Categories