Haftanın sorusu 3

Başlatan Erdem, 19 Ocak 2017 - 09:01:50

« önceki - sonraki »

0 Üyeler ve 1 Ziyaretçi konuyu incelemekte.

Erdem

Sanırım bu serinin 3. sorusu olabilir. Merak edenler önceki başlıklara bakabilirler.

https://forum.ubuntu-tr.net/index.php?topic=27239

https://forum.ubuntu-tr.net/index.php?topic=51052.0

Sorunun çözümünü C, C++ Rust veya D ile yazabilirsiniz.

Soru şu: Bir klasör içinde /eski ve /yeni isminde dizinlerimiz var. /eski dizininde *.d uzantılı kaynak dosyalarımız var. Başka uzantılı dosyalar da olabilir.

/eski dizinindeki sadece değiştirilmiş *.d dosyalarını  /yeni dizinine kopyalamak istiyoruz.

Örneğin ilk durumda /eski dizininin içeriği şu şekilde olsun.
Alıntı Yap$ ls -l
-rw-rw-r-- 1 erdem erdem 193 Oca 18 23:08 bir.d
-rw-rw-r-- 1 erdem erdem  64 Oca 18 23:07 uc.d
-rw-rw-r-- 1 erdem erdem  49 Oca 18 22:53 iki.d
-rw-rw-r-- 1 erdem erdem   2 Oca 19 08:53 deneme.txt

Bu durumda program hiç bir şey yapmıyor. Bir metin düzenleyici ile bir.d ve uc.d kütüğünde değişiklik yaptık. Bu iki kaynak dosyasını /yeni dizinine kopyalamasını istiyoruz.

Ayrıca üzerinde değişiklik yaptığımız ve /yeni  dizinine kopyaladığımız kaynak dosyalarının çetelesini de tutmak istiyoruz. Bu nedenle programımız değişiklik olan kaynak dosyalarının bir listesini örneğin degisenler.txt isminde bir kütükte tutsun istiyoruz.
// degisenler.txt

Alıntı Yapeski/bir.d
eski/uc.d

Erdem

Henüz kimse yanıt yazmamış. Ama ben D ile bu örneği kodladım  8)

Merak edenler bakabilir  ;)

http://ddili.org/forum/post/12475

erdemakin09

Güzel bir soru olmuş. Kod olarak yazmadım ama aklıma ilk gelen bir template dosyası oluşturup sonra onun üzerinden kontrolünü yapmak oldu. Senin kodunu da baktım okunabilir bir kod olmuş ama d dilini pek bilmiyorum. Yorum satırları ile desteklersen kodunu daha güzel olur benim gibi bilmeyenler için :)

Açıkcası c/c++ ilgilimi kaybediyorum gerek işimden gerek rubynin beni fazla cezbetmesinden dolayı :) Fakat burada yaptığın bu güzel etkinliğin bir benzerini ruby içinde ben yapmayı düşünüyorum. Biraz daha ustalaşayım da :D
Her Can Bir Gün Ölümü Tadacaktır!

Erdem

Programı anlatmak için D'nin UCFS denilen denk işlev çağırma biçimini anlamak gerekiyor.

import std.stdio;

void pişir(string isim)
{
writeln(isim ~ " pişiriyorum");
}

void main()
{
pişir("çorba");
("çay").pişir; /+ parantezleri yazmadım dikkat ederseniz +/
("ekmek").pişir;
}


Örneğin bu ilk işlevi birinci şekilde C, C++'ya benzer şekilde yazabileceğimiz gibi daha esnek bir biçimde kullanabiliyoruz.


import std.stdio;
import std.path;
import std.algorithm;
import std.file;

void main()
{
        ("eski/")
        .dirEntries(SpanMode.depth)
        .filter!(kütük => kütük.extension == ".d")
        .each!writeln;       
}


Bizim programın özü de bu. eski/ dizindeki DFS arama algoritması ile kütükleri listeliyor. Sonra .filter ile d uzantılıları seçiyor. each! ile herbirini yazıyor. Bunu denemek için örneğin .filter!'la başlayan satırı silerek görebilirsiniz.

import std.stdio: writeln, writefln;
import std.file: getTimes;
import std.algorithm: filter, map, each;
import std.path: dirEntries, SpanMode, extension;
import std.datetime: SysTime, DateTime;
import std.typecons: tuple;

SysTime sonDeğişiklikZamanı(string kütükİsmi)
{
    SysTime sonErişimZamanı;
    SysTime sonDeğişiklikZamanı;
    kütükİsmi.getTimes(sonErişimZamanı, sonDeğişiklikZamanı);
    return sonDeğişiklikZamanı;
}

void main()
{
const arananZaman = SysTime(DateTime(2017, 1, 22));

("eski/")
    .dirEntries(SpanMode.shallow)
        .filter!(isim => isim.extension == ".d")
        .map!(isim => tuple(isim, isim.sonDeğişiklikZamanı))
        .filter!(çokuzlu => çokuzlu[1] > arananZaman)
        .each!writeln;
}


Programı daha da geliştirirsek burada sonDeğişiklikZamanı işlevi basitçe bir kütüğün en son değiştiği zamanı veriyor. Burada örneğin 22 Ocak'tan sonra değişen dosyaları süzüyoruz.

Genel olarak bu konu D'nin ileri düzey olanaklarından faydalanıyor. Merak edenler buradan okuyabilirler.

http://ddili.org/ders/d/araliklar.html
http://ddili.org/ders/d/araliklar_baska.html

erdemakin09

Bilgilendirme için teşekkürler adaş :)
Her Can Bir Gün Ölümü Tadacaktır!

ShangriLa

#5
Sistem programlama yapıp rust'u dahil etmemek ayıp olur :D

Idiomatic olmayan fonksiyonel rust sürümü:

use std::fs::{File, read_dir, remove_file, hard_link};
use std::io::Write;
use std::path::Path;
fn main() {
    // değişikliklerin kaydedileceği kütük dosyası
    let mut kutuk = File::create("degisiklikler.txt").unwrap();
    // eski dizini okunur
    for degisen in read_dir("./eski").unwrap()
        // dosya uzantısı "d" olan dosyalar filtrelenir
        .filter(|de| de.as_ref().map(|de| de.path().extension().unwrap() == "d").unwrap())
        .filter_map(|de| {
            // yeni dizinindeki dosyanın yolu
            let p = Path::new("./yeni").join(de.as_ref().unwrap().path().file_name().unwrap());
            // eski dizinde okunan dosya yeni dizinde yoksa veya değiştirilme zamanı değişikse
            if !p.exists() ||
                p.metadata().unwrap().modified().unwrap() !=
                    de.as_ref().unwrap().metadata().unwrap().modified().unwrap() {
                remove_file(&p).ok();
                // yeni dizine hard_link olarak kopyalanır (değiştirilme zamanıyla birlikte)
                hard_link(de.as_ref().unwrap().path(), p).unwrap();
                Some(de.as_ref().unwrap().path())
            } else {
                None
            }
        }) {
        // degisen dosyanın yolu kütüğe yazılır
        writeln!(kutuk, "{}", degisen.to_str().unwrap()).unwrap();
        println!("Değişen dosya: {:?} kopyalandı", degisen);
    }
}


Idomatic olan dekleratif rust sürümü:

use std::fs::{File, read_dir, hard_link, remove_file};
use std::io::{Write, Error, ErrorKind};
use std::path::Path;

fn erdemin_d_dosyalarini_kopyala<P: AsRef<Path>>(eski: P, yeni: P) -> Result<(), Error> {
    // değişikliklerin kaydedileceği kütük dosyası
    let mut kutuk = try!(File::create("degisiklikler.txt"));

    for de in try!(read_dir(eski.as_ref())) {
        let de = try!(de);

        // dosya uzantısı "d" olmayan dosyalar geçilir
        if try!(de.path().extension().ok_or(Error::from(ErrorKind::Other))) != "d" {
            continue;
        }

        // yeni dizinindeki dosyanın yolu
        let p = Path::new(yeni.as_ref())
            .join(try!(de.path().file_name().ok_or(Error::from(ErrorKind::Other))));

        // eski dizinde okunan dosya yeni dizinde yoksa veya değiştirilme zamanı değişikse
        if !p.exists() ||
           try!(p.metadata().and_then(|p| p.modified())) !=
           try!(de.metadata().and_then(|p| p.modified())) {

            let _ = remove_file(&p);

            // yeni dizine hard linklenir (değiştirilme zamanıyla birlikte vs kopyalanır)
            try!(hard_link(de.path(), p));

            // degisen dosyanın yolu kütüğe yazılır
            let degisen =
                try!(de.path().to_str().map(|s| s.to_owned()).ok_or(Error::from(ErrorKind::Other)));
            try!(writeln!(kutuk, "{}", degisen));
            println!("Değişen dosya: {:?} kopyalandı", degisen);
        }
    }
    Ok(())
}

fn main() {
    erdemin_d_dosyalarini_kopyala("./eski", "./yeni").expect("IO hatası");
}
Ubuntu Mate Trusty

Erdem

Alıntı yapılan: ShangriLa - 23 Ocak 2017 - 14:19:44
Sistem programlama yapıp rust'u dahil etmemek ayıp olur :D

Idiomatic olmayan fonksiyonel rust sürümü:

[...]

Teşekkürler! :)

Bu programı denedim.

$ rustc deneme.rs

$ ./deneme
Değişen dosya: "./eski/iki.d" kopyalandı
Değişen dosya: "./eski/deneme.d" kopyalandı
Değişen dosya: "./eski/bir.d" kopyalandı

Ama ilk seferde tüm dosyaları kopyalamaması gerekiyordu  ;)

ShangriLa

Benim program değiştirilme zamanına baktığı için sizin daha önce yeni dizinine kopyalanmış olan dosyaların kopyalama methodu farklı olmuş olacağından ilk defada bunu düzeltmek için kopyalama yapmıştır.

Örneğin "cp eski/deneme.d yeni/deneme.d" derseniz bu yeni/deneme.d nin değiştirilme zamanını şu an yapar. Bu da benim programa göre yeni/deneme.d farklı bir dosya anlamına geliyor.

Fakat "ln eski/deneme.d yeni/deneme.d" derseniz tüm dosya durumlarıyla (hard link) kopyalamış olursunuz. Program bu özellikten yararlanarak değişiklikleri algılıyor.
Ubuntu Mate Trusty

Erdem

Aslında pratikte ilk seferinde dosyaları kopyalanmamasının daha iyi bir çözüm olduğunu düşünüyorum.

Örneğin ben bu programın biraz değişik sürümünü kullanıyorum. Bir dizinde yüzlerce kaynak dosyası var. Kopyalamadan önce make komutunu çalıştırıyor. Bu da diyelim ki sadece bir tane kaynak dosyası değişmişse kısa bir derleme yapıyor. Sonra oluşan kütüphane dosyasını da başka bir dizine kopyalıyor. Ama tüm kaynak dosyalarını derlerseniz yaklaşık yarım saat sürüyor  ;)

Ben şöyle bir çözüm geliştirdim. Programı ilk çalıştırdığımızda eğer yoksa degisiklikler.txt isminde bir kütük oluşturuyor ve içine o anki saati yazıyor. Örneğin:

2017-Jan-24 22:07:05.432577

Diyelim ki eski dizinindeki deneme.d kütüğünde değişiklik yaptık. Tekrar degisiklikler.txt dosyasına kontrol zamanını ve kütük ismiyle kütüğün değiştiği saati yazıyor.

2017-Jan-24 22:09:23.5360845
eski/deneme.d: 2017-Jan-24 22:08:55.1168591

Tabi bu kütük degisenler.txt listesinde yoksa bu listeye de eklemesi gerekiyor.

eski/deneme.d

Ben de bu vesileyle Rust derleyicisini denemiş oldum  ;)