Living life and Make it Better

life, learn, contribute

Endy Muhardin

Software Developer berdomisili di Jabodetabek, berkutat di lingkungan open source, terutama Java dan Linux.

Subversion backup script untuk Windows

Dulu saya pernah menulis tentang cara backup repository Subversion secara otomatis. Tetapi, script yang ada di situ hanya bisa dijalankan di Linux, karena ada satu baris bermasalah pada Perl scriptnya, yaitu:

$next_backup_file = "daily-incremental-backup." . date +%Y%m%d;

Baris di atas akan menjalankan perintah operating system seakan-akan kita menjalankan perintah ini di command prompt: $ date +%Y%m%d

Di Linux, perintah ini berjalan lancar, menampilkan output sebagai berikut: 20060515

Output tersebut nantinya digunakan untuk membentuk nama file dump. Tetapi di Windows, hasilnya adalah: The system cannot accept the date entered .. blablabla Rupanya Windows mengira kita akan ganti tanggal komputer.

Jadi akhirnya, karena saya tidak mengerti Perl, saya membuat backup script baru dengan Ruby. Logika yang sama, alur program yang sama, cuma beda bahasa. Inilah hasilnya. Silahkan digunakan dan dimodifikasi sesuai kebutuhan.

svn-weekly-backup.rb

# Full Backup script for Subversion Repository #
require 'date'

# 1. Initialize variables
backup_folder = "c:/Backup"
repo_folder = "c:/Repository/Imagine"
youngest = `svnlook youngest #{repo_folder}`.strip
next_backup_file = "weekly-full-backup.#{Time.now.strftime("%Y%m%d")}.dmp"
compress_script = backup_folder+"/compress-"+youngest+".tzs"
compress_command = "C:/Program Files/TUGZip/TzScript.exe #{compress_script}"


# 2. Perform backup
puts "Backing up to revision #{youngest}\n";
result = `svnadmin dump #{repo_folder} > #{backup_folder}/#{next_backup_file}`

# 3. Compress backup result
# 3.1 Creating temporary zip script [TugZip  Required]  
puts "Generating compress script ...\n";
tzs_file = < <-TZS
		function main()
		{
		     var Comp = new Compress();
		     Comp.Archive = "#{backup_folder}/#{next_backup_file}.zip";
		     Comp.Type = "ZIP";
		     Comp.Compression = 3;
		     Comp.WorkingDir = "#{backup_folder}";
		     Comp.Data = "#{next_backup_file}";
		     Comp.Password = "";
		     Comp.DateExtension = 0;
		     Comp.TimeExtension = 0;
		     Comp.Overwrite = 1;
		     Comp.Recurse = 0;
		     Comp.StoreFolderNames = 1;
		     Comp.IncludeHiddenFiles = 1;
		     Comp.DoCompress();
		}
	TZS
File.open(compress_script, "w") do | file |
    file << tzs_file	
end

# 3.2. Executing compression
puts "Compressing dump file...\n";
puts `#{compress_command}`

# 3.3. Deleting temporary zip script 
puts "Deleting compress script ...\n";
File.delete(compress_script);

# 3.4 Deleting uncompressed dump file
puts "Deleting uncompressed dump file ...\n";
File.delete(backup_folder+"/"+next_backup_file);

# 4. Write last backup position to marker file
File.open(backup_folder+"/last_backed_up", "w") do | file |
    file << youngest
end

svn-daily-backup.rb

# Full Backup script for Subversion Repository #
require 'date'

# 1. Initialize variables
backup_folder = "c:/Backup"
repo_folder = "c:/Repository/Imagine"
youngest = `svnlook youngest #{repo_folder}`.strip
next_backup_file = "daily-incremental-backup.#{Time.now.strftime("%Y%m%d")}.dmp"
compress_script = backup_folder+"/compress-"+youngest+".tzs"
compress_command = "C:/Program Files/TUGZip/TzScript.exe #{compress_script}"

# 1.a. Get last backed up revision
last_backup = 0;
if File.exist?(backup_folder+"/last_backed_up")
	File.open(backup_folder+"/last_backed_up", "r") do | file |
	    while line = file.gets
			last_backup = line.strip.to_i
		end
	end
end


# 2. Perform backup
if last_backup == youngest.to_i
	puts "No new revision since last backup .. exiting"
	exit 0; 
end

start_backup = last_backup + 1

puts "Backing up from revision #{last_backup} to revision #{youngest}\n";
result = `svnadmin dump --incremental --revision #{last_backup}:#{youngest} #{repo_folder} > #{backup_folder}/#{next_backup_file}`

# 3. Compress backup result
# 3.1 Creating temporary zip script [TugZip  Required]  
puts "Generating compress script ...\n";
tzs_file = < <-TZS
		function main()
		{
		     var Comp = new Compress();
		     Comp.Archive = "#{backup_folder}/#{next_backup_file}.zip";
		     Comp.Type = "ZIP";
		     Comp.Compression = 3;
		     Comp.WorkingDir = "#{backup_folder}";
		     Comp.Data = "#{next_backup_file}";
		     Comp.Password = "";
		     Comp.DateExtension = 0;
		     Comp.TimeExtension = 0;
		     Comp.Overwrite = 1;
		     Comp.Recurse = 0;
		     Comp.StoreFolderNames = 1;
		     Comp.IncludeHiddenFiles = 1;
		     Comp.DoCompress();
		}
	TZS
File.open(compress_script, "w") do | file |
    file << tzs_file	
end

# 3.2. Executing compression
puts "Compressing dump file...\n";
puts `#{compress_command}`

# 3.3. Deleting temporary zip script 
puts "Deleting compress script ...\n";
File.delete(compress_script);

# 3.4 Deleting uncompressed dump file
puts "Deleting uncompressed dump file ...\n";
File.delete(backup_folder+"/"+next_backup_file);

# 4. Write last backup position to marker file
File.open(backup_folder+"/last_backed_up", "w") do | file |
    file << youngest
end

Langkah terakhir, buat bat script sederhana untuk mengeksekusi script ruby ini. Dengan adanya bat script, kita bisa dengan mudah menambahkan entri di Windows Scheduler untuk dijalankan secara otomatis dan terjadwal.

svn-weekly-backup.bat

ruby C:\Backup\svn-weekly-backup.rb

daily-full-backup.bat

ruby C:\Backup\svn-daily-backup.rb

Terakhir, buat folder c:\Backup dan letakkan file-file berikut dalam folder tersebut:

  • svn-weekly-backup.rb

  • svn-daily-backup.rb

  • svn-weekly-backup.bat

  • svn-daily-backup.bat

Sistem backup Anda siap digunakan.

Buat yang malas copy-paste, silahkan download keempat file tersebut [tar.bz2 1.4 KB].

** Perhatian: Untuk menjalankan kode ini dengan baik, Anda harus menginstal aplikasi TugZIP. Ini dibutuhkan untuk mengkompres file hasil dump. Buat yang lebih suka WinZip, WinRAR, atau aplikasi kompresi yang lain, silahkan memikirkan cara memanggilnya dari command prompt dan memodifikasi kode program di atas, yaitu bagian #3: Compress Backup Result.

Selain itu, Anda juga harus menginstal bahasa pemrograman Ruby. Installernya bisa didownload di sini. **

Selamat menggunakan, semoga bermanfaat :D


Aplikasi Portabel

Masih ingat jaman DOS dulu? Untuk menyalakan komputer kita harus memasukkan floppy disk yang lebar. Setelah komputer selesai booting, kalau kita ingin mengetik, ganti disket booting dengan disket berisi aplikasi Wordstar. Selesai mengetik, ingin menyimpan dokumen, ganti disket Wordstar dengan disket data. Capek bekerja, ingin main game, masukkan disket berisi Digger.

Hidup begitu mudah dan sederhana. Satu aplikasi muat di dalam satu disket. Berbeda dengan jaman sekarang. Harus instal dulu semua aplikasi. Kalau sudah tidak digunakan dan harddisk penuh, uninstal lagi. Lama-lama registry jadi berantakan dan akibatnya komputer jadi lemot.

Selain itu, kadang ada beberapa di antara kita yang kurang beruntung. Tidak bisa instal aplikasi di komputer yang sedang digunakan. Sebabnya bisa macam-macam. Ada yang dilarang kantor, ada juga yang cuma pinjam komputer sebentar, sehingga kalo mau instal aplikasi rasanya kurang sopan. Masa cuma pinjam 5 menit saja pakai instal-instal segala.

Nah, sekarang ada solusi jitu. Namanya aplikasi portabel. Artinya, aplikasi ini cukup dicopy ke USB disk dan bisa langsung dijalankan tanpa perlu instalasi.

Ada banyak aplikasi yang disertakan di dalamnya, antara lain:

  • Gaim: untuk chatting

  • Firefox: untuk browsing

  • Thunderbird: untuk email

  • OpenOffice: untuk menggantikan MS Office

  • dan masih banyak lagi.

Silahkan langsung ke websitenya


PrtScr di Linux

Membuat screenshot di Windows itu gampang. Tinggal ikuti langkah-langkah yang dijelaskan Oom Mbot, beres. Tapi bagaimana caranya membuat screenshot di Linux?

Gampang, jika Anda pengguna KDE, instal saja KSnapshot. Ini adalah aplikasi kecil yang bisa menangkap tampilan layar.

KSnapshot

Ada beberapa mode yang bisa digunakan, yaitu Full Screen, Region, dan Window under cursor. Full screen menangkap seluruh layar, termasuk menunya. Window under cursor hanya menangkap aplikasi yang sedang kita gunakan. Sedangkan Region hanya menangkap wilayah yang kita pilih saja.

KSnapshot Mode

Bagaimana kalau kita mau menampilkan popup-menu klik-kanan? Gampang, atur saja delay menjadi beberapa detik. Kemudian klik New Snapshot, dan lakukan klik kanan di aplikasi yang diinginkan. Selang beberapa detik kemudian, KSnapshot akan menangkap gambar.

Berbeda dengan di Windows, di Linux tombol PrtScr tidak secara otomatis menangkap tampilan layar. Tetapi masalah ini mudah diatasi. Kita dapat menyambungkan tombol PrtScr dengan KSnapshot, sehingga apabila tombol tersebut kita tekan, KSnapshot akan muncul.

Caranya, klik kanan tombol K di pojok kiri bawah. Kemudian pilih Menu Editor

Right Click K

Di panel sebelah kiri, cari aplikasi KSnapshot. Di Debian Sarge, biasanya KSnapshot ada di Graphics, Other Application. Begitu ketemu, langsung saja klik.

Menu Editor - Left Pane

Di panel sebelah kanan akan muncul keterangan tentang aplikasi. Kita akan mengatur Shortcut Key, letaknya di baris paling bawah.

Menu Editor - Right Pane

Klik tombol shortcutnya, akan muncul dialog kecil. Di sini kita bisa langsung tekan tombol PrtScr. Kemudian klik OK.

Edit Shortcut

Selesai sudah. Sekarang setiap kali tekan PrtScr, KSnapshot akan segera beraksi.

Pembaca yang teliti akan berpikir, “Bagaimana caranya menangkap gambar KSnapshot itu sendiri? Padahal ketika kita tekan New Snapshot pasti KSnapshot akan menghilang.”

Gampang, jalankan saja dua KSnapshot sekaligus. Yang satu untuk di-capture, satu lagi untuk meng-capture. :D


Hello Hibernate Annotation

Adanya fitur annotation di Java 5 membuka dunia baru bagi para coder Java. Dulu semua metadata mau tidak mau harus disimpan di XML file. Sekarang ada pilihan baru, kita bisa taruh di XML file, atau juga bisa di source code melalui annotation.

Salah satu implementasinya adalah annotation untuk hibernate untuk mendefinisikan mapping Hibernate. Sekarang kita tidak perlu lagi membuat *.hbm.xml untuk menyatakan mapping antara Java class dengan tabel di database.

Mari kita lihat kodenya.

Category.java

package id.web.endy.tutorial;

public class Category {
  private Integer id; 
  private String name;
  private String description; 

  public String getDescription() {
    return description;
  }

  public void setDescription(String description) {
    this.description = description;
  }

  public Integer getId() {
    return id;
  }
	
  public void setId(Integer id) {
    this.id = id;
  }
  
  public String getName() {
    return name;
  }

  public void setName(String name) {
    this.name = name;
  }
}

Class di atas akan kita simpan ke database dengan skema tabel (MySQL) sebagai berikut:

Category-ddl.sql

CREATE TABLE Category (
  id INT PRIMARY KEY AUTO_INCREMENT, 
  name VARCHAR(255), 
  description VARCHAR(255)
);

Sebelum jaman annotation, kita harus buat mapping file sebagai berikut.

Category.hbm.xml

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
    "-//Hibernate/Hibernate Mapping DTD//EN"
    "http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd">
    
<hibernate-mapping>
  <class name="id.web.endy.tutorial.Category" table="Category">
    <id name="id" column="id">
      <generator class="auto"/>
    </id>
    <property name="name" column="name"/>
    <property name="name" column="description"/>
</class>
</hibernate-mapping>

Tapi dengan menggunakan annotation, kita bisa lupakan file Category.hbm.xml. Sebagai gantinya, kita tambahkan sedikit annotation pada class Category sebagai berikut

Category.java dengan Annotation

package id.web.endy.tutorial;

@Entity
public class Category {
  private Integer id; 
  private String name;
  private String description; 

  public String getDescription() {
    return description;
  }

  public void setDescription(String description) {
    this.description = description;
  }

  @Id(generate=GeneratorType.AUTO)
  public Integer getId() {
    return id;
  }
	
  public void setId(Integer id) {
    this.id = id;
  }
  
  public String getName() {
    return name;
  }

  public void setName(String name) {
    this.name = name;
  }
}

Perbedaan pada kode di atas cuma dua baris saja, yaitu:

  • @Entity
  • @Id(generate=GeneratorType.AUTO)

Selain untuk property dan id biasa, hibernate annotation juga dapat digunakan untuk one-to-many, many-to-many, dan teknik-teknik advanced lainnya.


Booklet Printing

Jika Anda adalah kolektor PDF obsesif-kompulsif seperti saya, pasti cepat atau lambat Anda akan mencari cara yang paling efektif untuk mencetak koleksi PDF tersebut.

Misalnya, kita punya Tutorial PHP-MySQL seperti pada gambar berikut

Modul PHP

Berhubung ada 81 halaman di file tersebut, kita ingin menghemat kertas dengan cara print bolak balik. Selain itu, kita juga mau cetak 2 halaman per lembar, sehingga yang tadinya seperti ini

Normal Page Print

menjadi seperti ini

Two Sheet per Page

Tapi sebetulnya, ada lagi yang lebih optimal, yaitu teknik yang dikenal dengan nama keren “booklet printing”, menjadikan susunan halaman menjadi seperti ini:

Booklet Print

Saya pernah membuat buku dengan cetakan seperti itu menggunakan printer Canon di Windows. Driver printer Canon tersebut sudah menyertakan fasilitas untuk melakukan booklet printing. Tetapi kalau menggunakan printer selain Canon, yah kita harus cari cara lain.

Setelah googling ke sana kemari, dengan menggunakan keyword “booklet printing kprinter”, akhirnya saya berhasil menemukan tutorial ini, yang menjelaskan cara melakukan booklet printing dengan KDE. Berikut langkah-langkahnya, saya contohkan dengan Acrobat Reader.

1. Buka Print Dialog, pilih kprinter sebagai print command, dan tekan Print

Acrobat Reader Print Dialog

2. Dialog KPrinter muncul, klik tombol Properties di pojok kanan atas

KPrinter Dialog

3. Pilih tab Filter, kemudian tambah filter baru dengan cara menekan tombok corong

KPrinter Properties

4. Tambah filter baru dengan cara menekan tombol corong

Untuk tahap pertama, yang dipilih adalah Pamphlet Printing - Even Page (step 1)

Pamphlet Printing - Even Page (step 1)

5. Balikkan kertas

Setelah hasil print keluar, balikkan susunan kertas dan letakkan kembali di printer. Untuk tahap ini, kita perlu trial-and error untuk mendapatkan teknik yang tepat. Coba print halaman 1-8 dulu sebagai percobaan.

6. Print sekali lagi

Lakukan langkah 1-6, dengan sedikit perbedaan. Pada langkah #6, pilih Pamphlet Printing - Odd Page (step 2)

Pamphlet Printing - Odd Page (step 2)

Selesai. Sekarang tinggal diberikan ke tukang jilid. :D