3

I wanted to have Automated Backup of Salesforce Environment which includes all of the code and configuration we get through the Eclipse project and then meta data Selection.

I used ANT scripts and Force.com migration tool.

I am currently using pre configured package.xml file for the components which are retrieved via * wild card. and another package.xml where I have mentioned components which supports the folders. In case there is any change in the folder structure in the org, I am planning to update this Package.xml manually so that in next retrieve call the backup have the correct code and configurations. Also to overcome the max limit exceeded I am using multiple retrieve calls with smaller packages.xml files.

This was the automated process which I am using.

But the error I am facing is for layout component Layout Error for layout component extract when I execute the retrieve command for layouts it shows the below error, however some of the layout are extracted and saved in the target directory. unable to find out the error for the layout component

3

As some layouts are being saved, the most likely cause is that one or more of the layouts has a name containing a character that is not valid in a Windows file name i.e. one of these:

\/:*?"<>|
  • oh yes that may be the point. Thanks for pointing it out. I will check and update if the problem was solved.thanks. – user3813 Oct 19 '13 at 19:17
1

As stated by Keith C, there characters that are invalid for Windows/DOS file names namely \/:*?&lt;&gt;| and also two periods .. in immediate sequence.

End-users seem to have a bad habit of naming reports with those characters. If added to the <sf:retrieve/> (assuming the namespace) element unzip="false" it will not unzip the retrieve_<insert job id>.zip.

To get the job id, I just regex with new Regex object or using [Regex]::Match if using C# or Powershell respectively "(?mi).*Request ID for the current retrieve task:\s*(?[A-Za-z0-9]{18})". Just get the "jobid" group and put the string in the appropriate place. Since my solution uses .Net, I use the ZipArchive class to individually process and rename the files using ExtractToFile(string, bool).

Other languages such as Python has other means to handle zip files such as ZipFile, but not necessarily a direct extract to file; although, one could open a new file for writing and then write the stream from zipfile.read(member), in theory. I typically replace the invalid characters with underscores, but there are numerous ways to carry it out according to one's needs.

Some untested sample code (with bad practices, no try/catch etc):

using System;
using System.IO;
using System.IO.Compression;
using System.IO.Compression.FileSystems;
using System.Diagnostics;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;

/* snip */
   // Hungarian notation is evil
   Regex rxJobId = new Regex(@"(?mi).*Request ID for the current retrieve task:\s*(?[A-Za-z0-9]{18})", RegexOptions.Compiled);
   Regex rxBadChars = new Regex(@"(?:[<>:""/\|?*]|\.\.|\.$", RegexOptions.Compiled);
   using (Process p = new Process()) {
       string[] para = new string[] {
           "/C",
           @""""+Path.Combine(Environment.GetEnvironmentVariable("ANT_HOME"), "bin", "ant.bat")+@"""",
           "retriveData" // Or whatever you named it in build.xml
       };

       p.StartInfo = new ProcessStartInfo(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.System), "cmd.exe"), string.Join(" ", parameters)) {
           UseShellExecute=false,
           RedirectStandardError=true,
           RedirectStardardOutput=true
       };
       bool failed = false;
       string jobId = null;
       p.Start();
       p.OutputDataReceived += new DataReceivedEventHander(
           (sender, e)=>{
                if ((""+e.Data).Length == 0) {
                   return;
                }
                if (e.Data.IndexOf("BUILD FAILED")>=0) {
                    failed = true;
                }
                Match m = rxJobId.Match(e.Data);
                if (m.Success) {
                   jobId = m.Groups["jobid"]?.ToString();
                }
           }
       );
       p.ErrorDataReceived += new DataReceivedEventHander(
           (sender, e)=>{
                if ((""+e.Data).Length == 0) {
                   return;
                }
                if (e.Data.IndexOf("BUILD FAILED")>=0) {
                    failed = true;
                }
                Match m = rxJobId.Match(e.Data);
                if (m.Success) {
                   jobId = m.Groups["jobid"]?.ToString();
                }
           }
       );
       p.BeginOutputReadLine();
       p.BeginErrorReadLine();
       while(p.WaitForExit(250)) {
           Thread.Sleep(250);
       }
       if (!failed && (""+jobId).Length > 0) {
           string filename = "retrieve_"+jobId+".zip";
           if (File.Exists(filename)) {
               using (ZipArchive archive = ZipFile.OpenRead(filename)) {
                    foreach(ZipArchiveEntry entry in archive.Entries) {
                         string upzipHere = Path.GetFullPath(Path.Combine("c:\destfolder", Path.GetDirectoryName(entry.FullName), rxBadChars.Replace(entry.Name, "_")));
                         entry.ExtractToFile(unzipHere, true); // I wanted overwrite
                    }
               }
           }
       }
   }
   /* snip */

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.