5

I noticed that cake support HTTP Operations, but no FTP Operations, do you know how to create a task to upload file via FTP?

user1633272
  • 2,007
  • 5
  • 25
  • 48

2 Answers2

12

There's nothing build in Cake today that provided functionality to transfer files using the FTP protocol.

Though if you're running Cake on "Full CLR" you can use the .NET framework built in FtpWebRequest to upload a file. The FtpWebRequest has not been ported to .NET Core so if you're running Cake.CoreCLR.

One way you could do this by creating an ftp.cake with a static FTPUpload utility method that you can reuse from your build.cake file.

Example ftp.cake

public static bool FTPUpload(
    ICakeContext context,
    string ftpUri,
    string user,
    string password,
    FilePath filePath,
    out string uploadResponseStatus
    )
{
    if (context==null)
    {
        throw new ArgumentNullException("context");
    }

    if (string.IsNullOrEmpty(ftpUri))
    {
        throw new ArgumentNullException("ftpUri");
    }

    if (string.IsNullOrEmpty(user))
    {
        throw new ArgumentNullException("user");
    }

    if (string.IsNullOrEmpty(password))
    {
        throw new ArgumentNullException("password");
    }

    if (filePath==null)
    {
        throw new ArgumentNullException("filePath");
    }

    if (!context.FileSystem.Exist(filePath))
    {
        throw new System.IO.FileNotFoundException("Source file not found.", filePath.FullPath);
    }

    uploadResponseStatus = null;
    var ftpFullPath = string.Format(
        "{0}/{1}",
        ftpUri.TrimEnd('/'),
        filePath.GetFilename()
        );
    var ftpUpload = System.Net.WebRequest.Create(ftpFullPath) as System.Net.FtpWebRequest;

    if (ftpUpload == null)
    {
        uploadResponseStatus = "Failed to create web request";
        return false;
    }

    ftpUpload.Credentials = new System.Net.NetworkCredential(user, password);
    ftpUpload.KeepAlive = false;
    ftpUpload.UseBinary = true;
    ftpUpload.Method = System.Net.WebRequestMethods.Ftp.UploadFile;
    using (System.IO.Stream
        sourceStream = context.FileSystem.GetFile(filePath).OpenRead(),
        uploadStream = ftpUpload.GetRequestStream())
    {
        sourceStream.CopyTo(uploadStream);
        uploadStream.Close();
    }

    var uploadResponse = (System.Net.FtpWebResponse)ftpUpload.GetResponse();
    uploadResponseStatus = (uploadResponse.StatusDescription ?? string.Empty).Trim().ToUpper();
    uploadResponse.Close();
    return  uploadResponseStatus.Contains("TRANSFER COMPLETE") ||
                     uploadResponseStatus.Contains("FILE RECEIVE OK");
}

Example usage build.cake

#load "ftp.cake"

string ftpPath = "ftp://ftp.server.com/test";
string ftpUser = "john";
string ftpPassword = "top!secret";
FilePath sourceFile = File("./data.zip");


Information("Uploading to upload {0} to {1}...", sourceFile, ftpPath);
string uploadResponseStatus;
if (!FTPUpload(
        Context,
        ftpPath,
        ftpUser,
        ftpPassword,
        sourceFile,
        out uploadResponseStatus
    ))
{
    throw new Exception(string.Format(
        "Failed to upload {0} to {1} ({2})",
        sourceFile,
        ftpPath,
        uploadResponseStatus));
}

Information("Successfully uploaded file ({0})", uploadResponseStatus);

Example output

Uploading to upload log.cake to ftp://ftp.server.com/test...
Successfully uploaded file (226 TRANSFER COMPLETE.)

FtpWebRequest is very basic so you might need to adapt it to you're target ftp server, but above should be a good starting point.

devlead
  • 4,935
  • 15
  • 36
5

Although I haven't tried it myself, I "think" I am right in saying that you can do file transfer operations using this Cake Addin. Definitely worth speaking to the original author of the addin about.

If not, your best best would be to create a custom addin for Cake, that provides the abilities that you are looking for.

There is a question over whether this should make it into the Core set of Cake functionality as well, however, the first course of action would be an addin.

Gary Ewan Park
  • 17,610
  • 5
  • 42
  • 60
  • 2
    Putty supports SCP/SFTP protocols but not FTP. – devlead Sep 21 '16 at 15:06
  • 1
    Surely SFTP would be preferred over FTP :-) – Gary Ewan Park Sep 21 '16 at 18:30
  • Agree, not always an option to change the server ;) – devlead Sep 21 '16 at 21:51
  • 1
    For other people interested in this plugin, what bothers me is that putty must be installed on the machine, and available in the PATH. When you're shipping a build script, imo it should be already ready to run. No install or configuration necessary on EACH machine that wants to run the script – Miiite Oct 18 '16 at 08:45
  • Tool resolution is built into Cake, however, there are some tools that require additional steps. One of those steps could be to download/install putty, and therefore the script could still be self-contained. – Gary Ewan Park Oct 18 '16 at 09:04