You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
433 lines
15 KiB
433 lines
15 KiB
public class MyApp.Window : Gtk.ApplicationWindow{
|
|
string laoutput;
|
|
bool upol;
|
|
public bool process_line (IOChannel channel, IOCondition condition, string stream_name, out string x, out bool y) {
|
|
if (condition == IOCondition.HUP) {
|
|
print ("%s: The fd has been closed.\n", stream_name);
|
|
return false;
|
|
}
|
|
|
|
try {
|
|
string line;
|
|
channel.read_line (out line, null, null);
|
|
print ("%s: %s", stream_name, line);
|
|
x = line;
|
|
y = true;
|
|
} catch (IOChannelError e) {
|
|
print ("%s: IOChannelError: %s\n", stream_name, e.message);
|
|
return false;
|
|
} catch (ConvertError e) {
|
|
print ("%s: ConvertError: %s\n", stream_name, e.message);
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
public Window(Nostalgia application){
|
|
Object(
|
|
application: application
|
|
);
|
|
}
|
|
construct{
|
|
bool ssnap=false;
|
|
var actualstack = new Gtk.Stack();
|
|
actualstack.expand = true;
|
|
var createstack = new Gtk.Stack();
|
|
createstack.expand = true;
|
|
var memc = new Gtk.Box(Gtk.Orientation.VERTICAL, 0);
|
|
var memr = new Gtk.Box(Gtk.Orientation.VERTICAL, 0);
|
|
var cr1 = new Gtk.Box(Gtk.Orientation.VERTICAL, 0);
|
|
var progresscr = new Gtk.Box(Gtk.Orientation.VERTICAL, 0);
|
|
//memr.add(new Gtk.Label("Restore"));
|
|
actualstack.add_titled(memc, "memc", "Create");
|
|
actualstack.add_titled(memr, "memr", "Restore");
|
|
createstack.add_titled(cr1, "cr1", "Backup Options");
|
|
createstack.add_titled(progresscr, "progresscr", "Snapshot Progress" );
|
|
actualstack.set_transition_type(Gtk.StackTransitionType.SLIDE_UP_DOWN);
|
|
actualstack.set_transition_duration(750);
|
|
createstack.set_transition_type(Gtk.StackTransitionType.SLIDE_UP_DOWN);
|
|
createstack.set_transition_duration(750);
|
|
//memc.set_column_homogeneous(true);
|
|
//memc.set_row_homogeneous(true);
|
|
|
|
|
|
//BACKUP MENU INTERFACE
|
|
var label1 = new Gtk.Label("<span size='xx-large' weight='bold'>Back up all your files and memories,
|
|
For when you need them the most</span>");
|
|
label1.set_use_markup(true);
|
|
memc.pack_start(label1, true, true, 50);
|
|
//memc.pack_start(new Gtk.Image.from_icon_name("liveusb-creator", Gtk.IconSize.DIALOG), false, false, 0);
|
|
memc.pack_start(new Gtk.Label("Nostalgia makes incremental snapshots, that means:
|
|
✔ Only the first snapshot contains the full file system
|
|
✔ All snapshots after the first only document changes
|
|
✔ It takes up significantly less space compared to full system snapshots
|
|
✔ You can hold lots of backups on a drive"), true, false, 0);
|
|
var button1 = new Gtk.Button.with_label("Create memory");
|
|
var blue_color = new Gdk.RGBA();
|
|
blue_color.parse("#0860F2");
|
|
var green_color = new Gdk.RGBA();
|
|
green_color.parse("#59C837");
|
|
var black_color = new Gdk.RGBA();
|
|
black_color.parse("#15161E");
|
|
button1.override_background_color(Gtk.StateFlags.NORMAL, green_color);
|
|
var gridfb = new Gtk.Grid();
|
|
gridfb.attach(button1, 1, 1);
|
|
button1.clicked.connect (() => {
|
|
createstack.set_visible_child(cr1);
|
|
print("Create Button Pressed \n");
|
|
remove(actualstack);
|
|
add(createstack);
|
|
createstack.set_visible_child(cr1);
|
|
var crtitlebar = new MyApp.HeaderBar(createstack);
|
|
set_titlebar(crtitlebar);
|
|
show_all();
|
|
});
|
|
gridfb.attach(new Gtk.Label(""), 2, 1);
|
|
gridfb.attach(new Gtk.Label(""), 0, 1);
|
|
gridfb.set_column_homogeneous(true);
|
|
gridfb.set_row_homogeneous(true);
|
|
//var img1 = new Gtk.Image.from_icon_name("liveusb-creator", Gtk.IconSize.DIALOG);
|
|
//memc.pack_start(img1, false, false, 30);
|
|
memc.pack_start(gridfb, true, true, 60);
|
|
|
|
|
|
var label1r = new Gtk.Label("<span size='xx-large' weight='bold'>For when the worst happens,
|
|
I'm here to get you back online</span>");
|
|
label1r.set_use_markup(true);
|
|
memr.pack_start(label1r, true, true, 50);
|
|
memr.pack_start(new Gtk.Label("You can use this option to restore your lost files
|
|
and configurations from any of your backups. Keep in mind
|
|
restoring your entire system using this tool may take a while,
|
|
so please be patient and let us get your system back and running"), true, false, 0);
|
|
var button1r = new Gtk.Button.with_label("Restore Memory");
|
|
button1r.override_background_color(Gtk.StateFlags.NORMAL, blue_color);
|
|
var gridfbr = new Gtk.Grid();
|
|
gridfbr.attach(button1r, 1, 1);
|
|
gridfbr.attach(new Gtk.Label(""), 0, 1);
|
|
gridfbr.attach(new Gtk.Label(""), 2, 1);
|
|
gridfbr.set_column_homogeneous(true);
|
|
gridfbr.set_row_homogeneous(true);
|
|
memr.pack_start(gridfbr, true, true, 60);
|
|
|
|
//CREATESTACK STUFF
|
|
cr1.pack_start(new Gtk.Label(""), false, false, 100);
|
|
var cr11 = new Gtk.Box(Gtk.Orientation.HORIZONTAL, 0);
|
|
//cr11.expand = true;
|
|
cr11.pack_start(new Gtk.Label(""), true, true, 40);
|
|
var cr1label = new Gtk.Label("<span size='x-large' weight='bold'>Select your backup drive:</span>");
|
|
cr1label.set_use_markup(true);
|
|
cr11.pack_start(cr1label, true, true, 10);
|
|
var crloc1 = new Gtk.FileChooserButton("Set location", Gtk.FileChooserAction.SELECT_FOLDER);
|
|
cr11.pack_start(crloc1, true, true, 0);
|
|
cr11.pack_start(new Gtk.Label(""), true, true, 10);
|
|
cr1.pack_start(cr11, false, false, 0);
|
|
cr1.pack_start(new Gtk.Label(""), false, false, 15);
|
|
var cr12 = new Gtk.Box(Gtk.Orientation.HORIZONTAL, 0);
|
|
var crbackbutton = new Gtk.Button.with_label("↩ Go back");
|
|
crbackbutton.clicked.connect (() => {
|
|
if (!ssnap){
|
|
print("Menu Button Pressed \n");
|
|
remove(createstack);
|
|
add(actualstack);
|
|
var hmtitlebar = new MyApp.HeaderBar(actualstack);
|
|
set_titlebar(hmtitlebar);
|
|
show_all();
|
|
string x;
|
|
//Process.spawn_command_line_sync("lsblk", out x);
|
|
//print(x);
|
|
}
|
|
});
|
|
cr12.pack_start(crbackbutton, false, false, 10);
|
|
/*var packhome = new Gtk.Switch();
|
|
packhome.set_state(true);
|
|
var cr14 = new Gtk.Box(Gtk.Orientation.HORIZONTAL, 0);
|
|
cr14.pack_start(new Gtk.Label(""), true, true, 10);
|
|
var packhomela = new Gtk.Label("<span size='x-large' weight='bold'>Include home folder in backup:</span>");
|
|
packhomela.set_use_markup(true);
|
|
cr14.pack_start(packhomela, false, false, 10);
|
|
cr14.pack_start(packhome, false, false, 10);
|
|
cr14.pack_start(new Gtk.Label(""), true, true, 10);
|
|
cr1.pack_start(cr14, false, false, 0);
|
|
*/
|
|
|
|
var cr15 = new Gtk.Box(Gtk.Orientation.VERTICAL, 20);
|
|
|
|
var ExcludePanel = new Gtk.ScrolledWindow(null, null);
|
|
|
|
var ExcludeListLabel = new Gtk.Label("Type Every Folder to be EXCLUDED from the Backup, using ABSOLUTE paths, one per line");
|
|
|
|
var ExcludeList = new Gtk.TextView();
|
|
ExcludeList.set_editable(true);
|
|
ExcludeList.set_cursor_visible(true);
|
|
ExcludeList.override_background_color(Gtk.StateFlags.NORMAL, black_color);
|
|
|
|
ExcludePanel.set_border_width(10);
|
|
ExcludePanel.set_max_content_height(100);
|
|
|
|
ExcludePanel.add(ExcludeList);
|
|
|
|
cr15.pack_start(ExcludeListLabel);
|
|
|
|
var cr151 = new Gtk.Box(Gtk.Orientation.HORIZONTAL, 20);
|
|
cr151.pack_start(new Gtk.Label(null), false, false, 5);
|
|
|
|
cr151.pack_start(ExcludePanel);
|
|
|
|
cr151.pack_start(new Gtk.Label(null), false, false, 5);
|
|
|
|
cr15.pack_start(cr151, false, false ,0);
|
|
|
|
cr1.pack_start(cr15, false, false, 0);
|
|
|
|
var finbutcr = new Gtk.Button.with_label("✔ Make snapshot");
|
|
finbutcr.override_background_color(Gtk.StateFlags.NORMAL, green_color);
|
|
cr12.pack_end(finbutcr, false, false, 10);
|
|
|
|
|
|
//CONFIG FILE
|
|
|
|
//var ExcludeFolders = ExcludeList.get_buffer().get_text(ExcludeList.get_buffer().get_start_iter(), ExcludeList.get_buffer().get_end_iter(), false);
|
|
|
|
//var ExcludeFolders = ExcludeList.buffer.text;
|
|
|
|
//print(ExcludeFolders);
|
|
|
|
var configData = "";
|
|
|
|
var configFolderLoc = GLib.Environment.get_home_dir().concat("/.config/nostalgia");
|
|
|
|
print(configFolderLoc);
|
|
|
|
File configFolder = File.new_for_path(configFolderLoc);
|
|
|
|
if(!configFolder.query_exists()) configFolder.make_directory();
|
|
|
|
var configFileLoc = configFolderLoc.concat("/exclude_list.txt");
|
|
|
|
File configFile = File.new_for_path(configFileLoc);
|
|
|
|
if(configFile.query_exists()){
|
|
//config file exists
|
|
print("\nREADING CONFIG FILE\n");
|
|
FileInputStream @is = configFile.read();
|
|
DataInputStream dis = new DataInputStream(@is);
|
|
string line;
|
|
print("\nFILE OPENED\n");
|
|
while((line = dis.read_line()) != null){
|
|
print("\nREAD LINE\n");
|
|
configData = configData.concat(line, "\n");
|
|
print("\nDONE\n");
|
|
}
|
|
if(configData == ""){
|
|
configFile.replace_contents("/dev\n/proc\n/sys\n/tmp\n/run\n/mnt\n/media\n/cdrom\n/lost+found\n\n".data, null, false, FileCreateFlags.NONE, null);
|
|
configData = "/dev\n/proc\n/sys\n/tmp\n/run\n/mnt\n/media\n/cdrom\n/lost+found\n\n";
|
|
}
|
|
ExcludeList.buffer.text = configData;
|
|
|
|
}else{
|
|
//no config file yet
|
|
configFile.create(FileCreateFlags.PRIVATE);
|
|
configFile.replace_contents("/dev\n/proc\n/sys\n/tmp\n/run\n/mnt\n/media\n/cdrom\n/lost+found\n\n".data, null, false, FileCreateFlags.NONE, null);
|
|
configData = "/dev\n/proc\n/sys\n/tmp\n/run\n/mnt\n/media\n/cdrom\n/lost+found\n\n";
|
|
ExcludeList.buffer.text = configData;
|
|
}
|
|
|
|
|
|
|
|
finbutcr.clicked.connect (() => {
|
|
if(!ssnap){
|
|
print(crloc1.get_filename());
|
|
string loc = crloc1.get_filename();
|
|
print("\n");
|
|
print(crloc1.get_filename());
|
|
if (crloc1.get_filename() == null){
|
|
var ibl = new Gtk.Dialog.with_buttons("Invaild backup location", this, Gtk.DialogFlags.MODAL | Gtk.DialogFlags.DESTROY_WITH_PARENT | Gtk.DialogFlags.USE_HEADER_BAR, null);
|
|
var iblca = ibl.get_content_area();
|
|
iblca.add(new Gtk.Label("
|
|
|
|
"));
|
|
iblca.add(new Gtk.Label(" Make sure the folder you picked is mounted and exists "));
|
|
iblca.add(new Gtk.Label("
|
|
|
|
"));
|
|
ibl.show_all();
|
|
|
|
}else{
|
|
ssnap=true;
|
|
createstack.set_visible_child(progresscr);
|
|
//string isfile;
|
|
//Process.spawn_command_line_sync("file " + crloc1.get_filename() + "/nostalgia.file", out isfile);
|
|
|
|
//DONE (dumb af that i didnt do this in the first place lazy ahh): Make this use fs syscalls instead of spawning a process
|
|
|
|
//string isft = crloc1.get_filename() + "/nostalgia.file: empty ";
|
|
|
|
File nostalgiaFile = File.new_for_path(crloc1.get_filename().concat("/nostalgia.file"));
|
|
|
|
|
|
bool isNostalgiaFile = nostalgiaFile.query_exists();
|
|
|
|
var lbl = new Gtk.TextView();
|
|
lbl.set_wrap_mode (Gtk.WrapMode.WORD);
|
|
//lbl.set_monospace(true);
|
|
lbl.override_background_color(Gtk.StateFlags.NORMAL, black_color);
|
|
|
|
var lblScroll = new Gtk.ScrolledWindow(null, null);
|
|
lblScroll.add(lbl);
|
|
lblScroll.set_max_content_height(600);
|
|
|
|
progresscr.pack_start(lblScroll);
|
|
|
|
var ProgBar = new Gtk.ProgressBar();
|
|
|
|
progresscr.pack_end(ProgBar);
|
|
|
|
var ProgLabel = new Gtk.Label("Nostalgia Progress: 0%");
|
|
|
|
progresscr.pack_end(ProgLabel);
|
|
|
|
|
|
if(!isNostalgiaFile){
|
|
print("\n root backup \n");
|
|
string testx;
|
|
//Process.spawn_command_line_sync("bash command", out testx);
|
|
progresscr.pack_start(new Gtk.Label(testx));
|
|
//print(testx);
|
|
progresscr.pack_start(new Gtk.Label("This seems to be your first nostalgia backup on this harddrive, so it will take a while"), false, false, 10);
|
|
show_all();
|
|
}
|
|
string[] spawn_env1 = Environ.get();
|
|
Pid rpid;
|
|
int otcr;
|
|
int dum;
|
|
bool lop=true;
|
|
|
|
ExcludeList.buffer.text = ExcludeList.buffer.text.concat("\n");
|
|
|
|
|
|
configFile.replace_contents(ExcludeList.buffer.text.data, null, false, FileCreateFlags.NONE, null);
|
|
|
|
string[] backup_command_template = {"/usr/bin/pkexec", "/usr/bin/rsync", "-ahv", "/home/ioachim/Music", "/home/ioachim/Music2", "--no-i-r", "--info=progress2", "--fsync", "--exclude-from=".concat(configFileLoc), null};
|
|
// --exclude-from="file.txt" EXCLUDES CONTENTS OF FILE EACH ON A LINE
|
|
//TODO: Replace command with proper one
|
|
|
|
|
|
var ChildProcessBackup = new Subprocess.newv(backup_command_template, SubprocessFlags.STDOUT_PIPE);
|
|
|
|
ChildProcessBackup.wait_check_async.begin(null, (obj, res) => {
|
|
try{
|
|
ChildProcessBackup.wait_check_async.end(res);
|
|
print("\n\n-------SUCCESFULL------\n\n");
|
|
|
|
ssnap = false;
|
|
createstack.set_visible_child(cr1);
|
|
Notify.init("Nostalgia");
|
|
var notification = new Notify.Notification("Nostalgia", "Your snapshot is ready", "deja-dup");
|
|
notification.set_timeout(0);
|
|
notification.show();
|
|
|
|
print("\nREMOVING CHILDREN FROM PAGE\n");
|
|
var progresscrChildren = progresscr.get_children();
|
|
foreach (Gtk.Widget element in progresscrChildren)
|
|
progresscr.remove(element);
|
|
|
|
|
|
}catch(Error err){
|
|
print("\n\n------ERROR!!!------\n%s\n\n", err.message);
|
|
|
|
createstack.set_visible_child(cr1);
|
|
|
|
var ibl = new Gtk.Dialog.with_buttons("Error Spawning Process", this, Gtk.DialogFlags.MODAL | Gtk.DialogFlags.DESTROY_WITH_PARENT | Gtk.DialogFlags.USE_HEADER_BAR, null);
|
|
var iblca = ibl.get_content_area();
|
|
iblca.add(new Gtk.Label("
|
|
|
|
"));
|
|
iblca.add(new Gtk.Label(" Make sure /usr/bin/rsync is installed, up to date and that you have root privileges and have inputed your correct user password "));
|
|
iblca.add(new Gtk.Label("
|
|
|
|
"));
|
|
ibl.show_all();
|
|
|
|
print("\nREMOVING CHILDREN FROM PAGE\n");
|
|
var progresscrChildren = progresscr.get_children();
|
|
foreach (Gtk.Widget element in progresscrChildren)
|
|
progresscr.remove(element);
|
|
|
|
ssnap = false;
|
|
}
|
|
});
|
|
|
|
|
|
var OutputPipeBackup = ChildProcessBackup.get_stdout_pipe();
|
|
|
|
update_label_from_istream.begin(OutputPipeBackup, lbl, ProgBar, ProgLabel);
|
|
|
|
}
|
|
}
|
|
});
|
|
cr1.pack_end(cr12, false, false, 10);
|
|
|
|
add(actualstack);
|
|
|
|
var headerbar = new MyApp.HeaderBar(actualstack);
|
|
set_titlebar(headerbar);
|
|
window_position = Gtk.WindowPosition.CENTER;
|
|
window_position = Gtk.WindowPosition.CENTER;
|
|
set_default_size(800, 600);
|
|
set_resizable(false);
|
|
show_all();
|
|
print("Hey, thanks for choosing nostalgia! \n");
|
|
print("If you're looking at the debug output most probably you're having some trouble with this program, so feel free to contact me and I'll see if I can help \n");
|
|
print("\n\n");
|
|
print("email: [ioachim.radu@protonmail.com]\n");
|
|
print("webpage: [ioachim.eu.org]\n");
|
|
print("pgp: [C2462D5103FA6059E1E3279C9E9299CD96C65EC6]\n");
|
|
print("\n\n");
|
|
}
|
|
}
|
|
|
|
int timer = 0;
|
|
|
|
async void update_label_from_istream (InputStream istream, Gtk.TextView label, Gtk.ProgressBar ProgBar, Gtk.Label ProgLabel) {
|
|
try {
|
|
|
|
var dis = new DataInputStream (istream);
|
|
var line = yield dis.read_line_async ();
|
|
while (line != null) {
|
|
if(timer == 5){
|
|
label.buffer.text = "";
|
|
timer = 0;
|
|
}
|
|
label.buffer.text += line + "\n";
|
|
print(line);
|
|
print("\n");
|
|
|
|
var words = line.split(" ");
|
|
|
|
foreach(unowned string word in words){
|
|
if(word[word.length - 1] == '%'){
|
|
var word_trimmed = word.substring(0, word.length - 1);
|
|
double procDone = (double)StrToInt(word_trimmed) / (double)100;
|
|
ProgBar.set_fraction(procDone);
|
|
ProgBar.set_text(word_trimmed);
|
|
ProgLabel.set_text(word_trimmed + "%");
|
|
|
|
print(procDone.to_string() + " ");
|
|
}
|
|
}
|
|
|
|
timer++;
|
|
line = yield dis.read_line_async ();
|
|
}
|
|
} catch (Error err) {}
|
|
}
|
|
|
|
|
|
int StrToInt(string str){
|
|
int ret = 0;
|
|
for(int i = 0; i < str.length; i++){
|
|
ret *= 10;
|
|
ret += (str[i] - '0'); //get char code offset to zero of digit
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|