Login

Automated Full Project Backup in Xcode

Automated Full Project Backup in Xcode

I have been going through a lot of tutorials lately. One thing I have noticed is when things go wrong after a chapter or two it is difficult to get back to where you were when things were working.

I have been giving Subversion a go but it is not as easy as you would think to roll back to a previous version. Plus I have to remember to do it. Two or three builds later and the lightbulb goes off, "When was the last time I committed to the repository?" Not good.

This script is very simple and should be used only for training or short build phases. The reason is that the entire project folder, minus the build folder, is backed-up during each build. Exactly what we need when wanting to roll back to the last chapter we were on in the book but not so good for large projects with hundreds of builds. I have a better, although not perfect by any means solution here.

How It Works

During each build you will be asked if you want to do a backup. If you click 'Yes' then another dialog will give you the opportunity to provide notes for this build. If you are doing tutorials this is a good place to put something like 'Just finished ch 4 page 95.' This will be added to a '_NOTES.txt' file inside this backup folder as well as added to an '_All_NOTES.txt' file inside the backup projects folder. This is for easy viewing of what you were doing during each build.

If you would like to disable the 'ask before backup' feature simply set ASK_BEFORE_BACKUP to false.

Installation

Installation instructions here.

Requirements

Rb-appscript

#!/usr/bin/env ruby -w

# Code from O'Reilly's 'Ruby Cookbook' page 220
# Versions file or folder names
# Eg. MyProj, MyProj.001, MyProj.002
class File
  def File.versioned_name(base, first_suffix='.0001')
    suffix = nil
    folder_name = base
    while File.exists?(folder_name)
      suffix = (suffix ? suffix.succ : first_suffix)
      folder_name = base + suffix
    end
    return folder_name
  end
end


class BackupXcodeProject
  require 'fileutils'
  require 'time'
  require 'appscript'; include Appscript
  require 'osax'; include OSAX

  MESSAGE_HEADER    = 'BACKING UP PROJECT MESSAGE'
  ASK_BEFORE_BACKUP = true

  def initialize
    instantiate_variables
  end

  def main_worker_bee
    backup_question if ASK_BEFORE_BACKUP
    create_parent_folder
    create_archive_folder
    create_versioned_folder
    add_notes
    copy_files
    delete_build_folder
  end

  def instantiate_variables
    @proj_dir               = ENV['PROJECT_DIR']
    @proj_name              = ENV['PROJECT_NAME']
    @backup_dir             = "#{ENV['HOME']}/desktop/BackupXcode"
    @time_format            = '24'
  end

  def create_parent_folder
    begin
      FileUtils.mkdir(@backup_dir) if !File.exists?(@backup_dir)
    rescue
      log_message("ERROR in create_parent_folder\nerror => #{$!}")
    end
  end

  def create_archive_folder
    begin
      @archive_folder_name = "#{@backup_dir}/#{@proj_name}"
      FileUtils.mkdir(@archive_folder_name) if !File.exists?(@archive_folder_name)
    rescue
      log_message("ERROR in create_archive_folder\nerror => #{$!}")
    end
  end

  def create_versioned_folder
    begin
      time_stamp = (@time_format == '24' ? `date +'%Y.%m.%d_%H.%M.%S'` : `date +'%Y.%m.%d_%I.%M.%S'`)
      folder_name = "#{time_stamp.chomp}_#{@proj_name}"
      @archive_versioned_name = File.versioned_name("#{@archive_folder_name}/#{folder_name}")
      FileUtils.mkdir(@archive_versioned_name)
    rescue
      log_message("ERROR in create_versioned_folder\nerror => #{$!}")
    end
  end
  
  def backup_question
    button = osax.display_dialog('Do you want to backup now?',
    :buttons => ['No', 'Yes'], 
    :default_button => 2)
    exit if button[:button_returned] == 'No'
  end

  def add_notes
    text = osax.display_dialog("Notes for this backup.", :default_answer => "\n\n\n\n\n")
    notes = text[:text_returned]
    all_notes = "\n------------------------------------\n#{File.basename(@archive_versioned_name)}\n\t#{notes}\n"
    open("#{@archive_folder_name}/_ALL_NOTES.txt", 'a') { |f| f.puts all_notes }
    open("#{@archive_versioned_name}/_NOTES.txt", 'w') { |f| f.puts notes }
  end

  def copy_files
      return system("/usr/bin/ditto #{@proj_dir} #{@archive_versioned_name}")
  end
  
  def delete_build_folder
    system("rm -r #{@archive_versioned_name}/build/")
  end

  def log_message(msg)
    puts "\n\n----------------------------------------------"
    puts MESSAGE_HEADER
    puts msg
    puts "----------------------------------------------\n\n"
  end

end


if __FILE__ == $0
  backup_files = BackupXcodeProjectFiles.new
  backup_files.main_worker_bee
  backup_files.log_message('Looks like all went well!')
end

Add comment


Security code
Refresh

 

Product Categories