I am a new user of perforce (coming from svn) and am using the gui interface p4v. I want to have a local copy of a folder in someone's depot but am unsure how to do so. I wish to end up with a local copy that is just for me to explore and look around. I do not wish for it be under revision control. Just need it to be as if i downloaded a folder from the internet, free to do whatever with it. How can i accomplish this in p4v?
Once you've synced the files, you can do whatever you want with them. Perforce marks files as read only unless you have them open for edit, so what I would do is sync the depot, copy it to a new location on your HDD, and then mark all the files writable.
Also, if all you want to do is look at the files, you could just sync the depot and open the files. You could even check them out (assuming you have permissions) and just not submit those changes if you wanted to tinker.
This 2 functions will help you start working.
public Repository GetRepository(string i_Workspace, string i_Username, string i_Password, string i_Server)
{
Repository rep;
Server server;
ServerAddress address;
// Create the repository
address = new ServerAddress(i_Server + ":1666");
server = new Server(address);
rep = new Repository(server);
rep.Connection.UserName = i_Username;
Perforce.P4.Options options = new Perforce.P4.Options();
options["Password"] = i_Password;
Environment.SetEnvironmentVariable("P4PASSWD", i_Password);
rep.Connection.Client = new Client();
if (i_Workspace != null && i_Workspace != string.Empty)
{
rep.Connection.Client.Name = i_Workspace;
}
rep.Connection.Connect(options);
rep.Connection.CommandTimeout = System.TimeSpan.Zero;
rep.Connection.Login(i_Password);
return rep;
}
private Client createWorkspace(string i_DepotPath, string i_RootDirectory)
{
string workspaceName = "workspace" + new Random().Next().ToString();
Repository rep = GetRepository(string.Empty);
Client client = new Client();
client.Name = workspaceName;
client.Root = i_RootDirectory;
client.OwnerName = k_DefaultUser;
client.ViewMap = new ViewMap();
client.Options = ClientOption.AllWrite;
client.LineEnd = LineEnd.Local;
client.SubmitOptions = new ClientSubmitOptions(false, SubmitType.SubmitUnchanged);
string depotPath = i_DepotPath + "/...";
String clientPath;
//clientPath = String.Format("//{0}/{1}/...", client.Name, i_DepotPath.Replace("//depot/", string.Empty));
clientPath = "//" + client.Name + "/...";
MapEntry entry = new MapEntry(MapType.Include, new DepotPath(depotPath), new ClientPath(clientPath));
client.ViewMap.Add(entry);
rep.CreateClient(client);
return client;
}
Related
I am developing an app that uploads PDF files to a specific Google Drive folder. The file name includes the current date. The following code is for my DriveServiceHelper.class that is used to create a folder in Google Drive and then upload the PDF files into that folder using its folderID:
public class DriveServiceHelper {
Calendar c = Calendar.getInstance();
Date d = c.getTime();
SimpleDateFormat df = new SimpleDateFormat("dd-MM-yyyy");
String currentDate = df.format(d);
String ps_FolderKey;
private final Executor mExecutor = Executors.newSingleThreadExecutor();
private Drive mDriveService;
public DriveServiceHelper(Drive mDriveService) {
this.mDriveService = mDriveService;
}
public Task<String> createFolder() {
return Tasks.call(mExecutor, () -> {
File folderMetadata = new File();
folderMetadata.setName("Covid Assessment Sheets");
folderMetadata.setMimeType("application/vnd.google-apps.folder");
File myFolder = null;
try {
myFolder = mDriveService.files().create(folderMetadata)
.setFields("id")
.execute();
System.out.println("Folder ID: " + myFolder.getId());
} catch (Exception e) {
e.printStackTrace();
}
if (myFolder == null) {
throw new IOException("Null result when requesting file creation");
}
ps_FolderKey = myFolder.getId();
return ps_FolderKey;
});
}
public Task<String> createFilePDF(String filePath, String folderId) {
return Tasks.call(mExecutor, () -> {
File fileMetaData = new File();
fileMetaData.setName("Covid Assessment # " + currentDate);
fileMetaData.setParents(Collections.singletonList(folderId));
java.io.File file = new java.io.File(filePath);
FileContent mediaContent = new FileContent("application/pdf", file);
File myFile = null;
try {
myFile = mDriveService.files().create(fileMetaData, mediaContent).execute();
} catch (Exception e) {
e.printStackTrace();
}
if (myFile == null) {
throw new IOException("Null result when requesting file creation");
}
return myFile.getId();
});
}
}
When uploading the same PDF to a Google Drive folder, I want to overwrite files with the same name, but instead duplicate files are created in the folder as the fileID assigned is different even if file name is the same.
Please help me understand how I should go about this, to automatically overwrite/replace files that already exist with the same name (each file is differentiated by date), and a new PDF file is created if the PDF file does not exist in the folder.
I understand that I might be using the deprecated Drive API, but I was unable to find other solutions online to help me implement what I need. I also came across solutions that include queries to search for existing Google Drive files, but I am not sure I understand how to use it to make it work for me.
Thank you
Google Drive supports multiple files with the same name
Thus, by creating a file with an already existing name, you will not automatically overwrite the old file.
Instead you should do the following:
Use the method Files:list with the query name = 'Covid Assessment Sheets' to find the already existing file(s) with the same name
If desired, you can narrow down the results by also specifying the mimeType and the parent folder (parents)
Retrieve the id of the list result(s)
Use the method Files:delete to delete the existing file
Proceed to create a new file as you are already doing
In Java this would look as following:
FileList result = DriveService.files().list()
.setQ("name = 'Covid Assessment Sheets'");
.setFields("files(id)")
.execute();
List<File> files = result.getFiles();
for (File file : files) {
DriveService.files().delete(file.getId()).execute();
}
An alternative approach would be to update the contents of the already existing file instead of creating a new one.
I have searched and found several examples of how to do this, but I can't make them work - well part of it doesn't work.
I can perform the file upload, but the following attempt to change properties fail.
I'm attempting to upload a file from a base64 payload - this part works - but when I afterwards attempt to edit the properties (custom column) associated with the file, the code fails.
Here is the code (simplified for readability):
(note that props is a collection of custom objects (FileProperty) with a name and a value attribute).
using (ClientContext context = new ClientContext("<sharepoint_server_url>"))
{
context.Credentials = new SharePointOnlineCredentials(<usr>,<secure_pwd>);
using (System.IO.MemoryStream ms = new System.IO.MemoryStream(Convert.FromBase64String(<base64_content>)))
{
File.SaveBinaryDirect(context, <relative_path>, ms, true);
}
// file is uploaded - so far so good!
// attempt to edit properties of the file.
if (props != null)
{
if (props.Count > 0)
{
File newFile = context.Web.GetFileByServerRelativeUrl(<relative_path>);
context.Load(newFile);
context.ExecuteQuery();
newFile.CheckOut();
ListItem item = newFile.ListItemAllFields;
foreach (FileProperty fp in props)
{
item[fp.name] = fp.value;
}
item.Update();
newFile.CheckIn(string.Empty, CheckinType.OverwriteCheckIn);
}
}
}
This code throws an exception in the part where I try to update the properties.
Message: The file was not found.
Can anyone tell me what is wrong with this example or provide another example on how to do this?
Also, a question - is there a way to address a file by a unique ID which is the same regardless of where in the SharePoint server the file is located or moved to?
I hope someone can help me out - thanks :)
Ok, I found a solution to my problem. I don't know why this works better, it just does.
For all I know, I'm doing the exact same thing, just in another way - maybe someone else who knows more about SharePoint than me (which isn't much) can explain why this works while the first example I posted doesn't.
Previous to the code shown, I ensure that <site_url> doesn't end with "/" and that <library_name> doesn't start or end with "/" and that <file_name> doesn't start or end with "/".
With the code below I can uplaod a file and update properties, in my case i changed "Title" and a custom column "CustCulomnA" and it workes.
using (ClientContext context = new ClientContext(<site_url>))
{
context.Credentials = new SharePointOnlineCredentials(<usr>, <secure_pwd>);
FileCreationInformation fci = new FileCreationInformation()
{
Url = <file_name>,
Content = Convert.FromBase64String(<base64_content>),
Overwrite = true
};
Web web = context.Web;
List lib = web.Lists.GetByTitle(<library_name>);
lib.RootFolder.Files.Add(fci);
context.ExecuteQuery();
response.message = "uploaded";
if (props != null)
{
if (props.Count > 0)
{
File newFile = context.Web.GetFileByUrl(<site_url> +"/"+ <library_name> + "/" + <file_name>);
context.Load(newFile);
context.ExecuteQuery();
newFile.CheckOut();
ListItem item = newFile.ListItemAllFields;
foreach (FileProperty fp in props)
{
item[fp.name] = fp.value;
}
item.Update();
newFile.CheckIn(string.Empty, CheckinType.OverwriteCheckIn);
context.ExecuteQuery();
Make sure the file server relative url is valid in this case.
For example if the complete url is:
https://zheguo.sharepoint.com/sites/test/Shared%20Documents/test.jpg
Then relative url should be
/sites/test/Shared%20Documents/test.jpg
And you can also use GetFileByUrl method, passing the complete file url like this:
clientContext.Credentials = new SharePointOnlineCredentials(userName, securePassword);
Web web = clientContext.Web;
clientContext.Load(web);
clientContext.ExecuteQuery();
File file = web.GetFileByUrl("https://zheguo.sharepoint.com/sites/test/Shared%20Documents/test.jpg");
clientContext.Load(file);
clientContext.ExecuteQuery();
file.CheckOut();
ListItem item = file.ListItemAllFields;
item["Title"] = "Test";
item.Update();
file.CheckIn(string.Empty, CheckinType.OverwriteCheckIn);
clientContext.ExecuteQuery();
}
When I am doing the search, the results always contain only five records (in ascending order). I need to get a list of all files in the folder. What am I doing wrong?
FileSearch fileSearch = new FileSearch();
FileSearchBasic fileSearchBasic = new FileSearchBasic();
// Specify the folder in which the search is to be done.
SearchMultiSelectField folderFilter = new SearchMultiSelectField
{
#operator = SearchMultiSelectFieldOperator.anyOf,
operatorSpecified = true
};
RecordRef[] folder = new RecordRef[1];
folder[0] = new RecordRef
{
// Internal id of the folder where pospay files are stored.
internalId = ns.DataCollection["netSuite:PositivePayFolderInternalId"]
};
folderFilter.searchValue = folder;
fileSearchBasic.folder = folderFilter;
fileSearch.basic = fileSearchBasic;
var result = NSBase.Client.Service.search(fileSearch);
var recordList = result.recordList; // this has ony five results, why?
I found the issue, 'PageSize' was set to 5 in the service client's constructor.
I'm creating a file in Acumatica by calling an action from the API, so that I can retrieve the file in my application.
Is it possible to delete the file via API after I'm done with it? I'd rather not have it cluttering up my Acumatica database.
Failing this, is there a recommended cleanup approach for these files?
Found examples of how to delete a file from within Acumatica, as well as how to save a new version of an existing file! The below implementation saves a new version but has the deletion method commented out. Because I built this into my report generation process, I'm not later deleting the report via API, but it would be easy to translate a deletion into an action callable by the API.
private IEnumerable ExportReport(PXAdapter adapter, string reportID, Dictionary<String, String> parameters)
{
//Press save if the SO is not completed
if (Base.Document.Current.Completed == false)
{
Base.Save.Press();
}
PX.SM.FileInfo file = null;
using (Report report = PXReportTools.LoadReport(reportID, null))
{
if (report == null)
{
throw new Exception("Unable to access Acumatica report writer for specified report : " + reportID);
}
PXReportTools.InitReportParameters(report, parameters, PXSettingProvider.Instance.Default);
ReportNode reportNode = ReportProcessor.ProcessReport(report);
IRenderFilter renderFilter = ReportProcessor.GetRenderer(ReportProcessor.FilterPdf);
//Generate the PDF
byte[] data = PX.Reports.Mail.Message.GenerateReport(reportNode, ReportProcessor.FilterPdf).First();
file = new PX.SM.FileInfo(reportNode.ExportFileName + ".pdf", null, data);
//Save the PDF to the SO
UploadFileMaintenance graph = new UploadFileMaintenance();
//Check to see if a file with this name already exists
Guid[] files = PXNoteAttribute.GetFileNotes(Base.Document.Cache, Base.Document.Current);
foreach (Guid fileID in files)
{
FileInfo existingFile = graph.GetFileWithNoData(fileID);
if (existingFile.Name == reportNode.ExportFileName + ".pdf")
{
//If we later decide we want to delete previous versions instead of saving them, this can be changed to
//UploadFileMaintenance.DeleteFile(existingFile.UID);
//But in the meantime, for history purposes, set the UID of the new file to that of the existing file so we can save it as a new version.
file.UID = existingFile.UID;
}
}
//Save the file with the setting to create a new version if one already exists based on the UID
graph.SaveFile(file, FileExistsAction.CreateVersion);
//Save the note attribute so we can find it again.
PXNoteAttribute.AttachFile(Base.Document.Cache, Base.Document.Current, file);
}
//Return the info on the file
return adapter.Get();
}
The response from Acumatica:
S-b (Screen-base) API allows clean way of downloading report generated as file. C-b (Contract-base) simply does not have this feature added. I suggest you provided feedback here: feedback.acumatica.com (EDIT: Done! https://feedback.acumatica.com/ideas/ACU-I-1852)
I think couple of workaround are:
1) use s-b using login from c-b to generate report and get as file (see example below), or
2) create another method to delete the file once required report file is downloaded. For that, you will need to pass back FileID or something to identify for deletion.
example of #1
using (DefaultSoapClient sc = new DefaultSoapClient("DefaultSoap1"))
{
string sharedCookie;
using (new OperationContextScope(sc.InnerChannel))
{
sc.Login("admin", "123", "Company", null, null);
var responseMessageProperty = (HttpResponseMessageProperty)
OperationContext.Current.IncomingMessageProperties[HttpResponseMessageProperty.Name];
sharedCookie = responseMessageProperty.Headers.Get("Set-Cookie");
}
try
{
Screen scr = new Screen(); // add reference to report e.g. http://localhost/Demo2018R2/Soap/SO641010.asmx
scr.CookieContainer = new System.Net.CookieContainer();
scr.CookieContainer.SetCookies(new Uri(scr.Url), sharedCookie);
var schema = scr.GetSchema();
var commands = new Command[]
{
new Value { LinkedCommand = schema.Parameters.OrderType, Value = "SO" },
new Value { LinkedCommand = schema.Parameters.OrderNumber, Value = "SO004425" },
schema.ReportResults.PdfContent
};
var data = scr.Submit(commands);
if(data != null && data.Length > 0)
{
System.IO.File.WriteAllBytes(#"c:\Temp\SalesOrder.pdf",
Convert.FromBase64String(data[0].ReportResults.PdfContent.Value));
}
}
finally
{
sc.Logout();
}
}
Hope this helps. Also, it would be great if you update the stackover post based on these suggestions.
Thanks
Nayan Mansinha
Lead - Developer Support | Acumatica
My code delete just files which parse to Jenkins name in the file. I would like to delete file based on the author (Jenkins) in the last commit. What is the best solution for that?
def changelogPath = "C:\\test"
def PackID = "test"
def delete(String changelogPath, String PackID) {
String folderPath = "$changelogPath"+ "\\" + "$PackID"
new File(folderPath).eachFile(FileType.FILES) { file ->
if (file.name.contains('Jenkins')) file.delete()
}
delete(changelogPath, PackID)
In order to find all files that have been changed with a certain commit, you need a diff of that commit with its predecessor.
You can let JGit compute a list of DiffEntries like this:
ObjectReader reader = git.getRepository().newObjectReader();
CanonicalTreeParser oldTreeIter = new CanonicalTreeParser();
ObjectId oldTree = git.getRepository().resolve( "HEAD^{tree}" );
oldTreeIter.reset( reader, oldTree );
CanonicalTreeParser newTreeIter = new CanonicalTreeParser();
ObjectId newTree = git.getRepository().resolve( "HEAD~1^{tree}" );
newTreeIter.reset( reader, newTree );
DiffFormatter df = new DiffFormatter( new ByteArrayOutputStream() );
df.setRepository( git.getRepository() );
List<DiffEntry> entries = df.scan( oldTreeIter, newTreeIter );
Each DiffEntry has a path that denotes the file which was added, changed, or deleted. The path is relative to the root of the working directory of the repository. Actually, there is an oldPath and newPath, see the JavaDoc which one to use when.
See also here for a general overview of JGit's diff API: http://www.codeaffine.com/2016/06/16/jgit-diff/