]> git.tdb.fi Git - builder.git/blob - source/cache.cpp
Refactor transitive dependencies to work on all targets
[builder.git] / source / cache.cpp
1 #include <msp/core/maputils.h>
2 #include <msp/fs/dir.h>
3 #include <msp/fs/stat.h>
4 #include <msp/fs/utils.h>
5 #include <msp/io/file.h>
6 #include <msp/io/print.h>
7 #include <msp/strings/utils.h>
8 #include "builder.h"
9 #include "cache.h"
10 #include "sourcepackage.h"
11 #include "target.h"
12
13 using namespace std;
14 using namespace Msp;
15
16 namespace {
17
18 unsigned read_count(IO::Base &in)
19 {
20         unsigned char head = in.get();
21         if((head&0xC0)==0xC0)
22         {
23                 unsigned char tail = in.get();
24                 return (head&0x3F)<<8 | tail;
25         }
26         else
27                 return head;
28 }
29
30 string read_string(IO::Base &in)
31 {
32         unsigned len = read_count(in);
33         char buf[0x4000];
34         len = in.read(buf, len);
35         return string(buf, len);
36 }
37
38 void write_count(IO::Base &out, unsigned count)
39 {
40         if(count<0xC0)
41                 out.put(count);
42         else if(count<0x4000)
43         {
44                 out.put(0xC0 | (count>>8));
45                 out.put(count&0xFF);
46         }
47         else
48                 throw invalid_argument("write_count");
49 }
50
51 void write_string(IO::Base &out, const string &str)
52 {
53         write_count(out, str.size());
54         out.write(str);
55 }
56
57 }
58
59
60 Cache::Cache(SourcePackage &p):
61         package(p),
62         filename(package.get_temp_directory()/"../cache"),
63         changed(false)
64 { }
65
66 void Cache::set_value(const Target *tgt, const string &k, const string &v)
67 {
68         ValueList vl;
69         vl.push_back(v);
70         set_values(tgt, k, vl);
71 }
72
73 void Cache::append_value(const Target *tgt, const string &k, const string &v)
74 {
75         Key key(tgt->get_name(), k);
76         DataMap::iterator i = data.find(key);
77         if(i==data.end())
78                 i = data.insert(DataMap::value_type(key, ValueList())).first;
79         i->second.push_back(v);
80         changed = true;
81         package.get_builder().get_logger().log("cache", format("Updated key %s %s+ %s", tgt->get_name(), k, v));
82 }
83
84 void Cache::set_values(const Target *tgt, const string &k, const ValueList &v)
85 {
86         data[Key(tgt->get_name(), k)] = v;
87         changed = true;
88         package.get_builder().get_logger().log("cache", format("Updated key %s %s: %s", tgt->get_name(), k, join(v.begin(), v.end())));
89 }
90
91 const string &Cache::get_value(const Target *tgt, const string &k)
92 {
93         const ValueList &values = get_values(tgt, k);
94         if(values.empty())
95                 throw logic_error("values.empty()");
96         return values.front();
97 }
98
99 const Cache::ValueList &Cache::get_values(const Target *tgt, const string &k)
100 {
101         return get_item(data, Key(tgt->get_name(), k));
102 }
103
104 bool Cache::has_key(const Target *tgt, const string &k)
105 {
106         return data.count(Key(tgt->get_name(), k));
107 }
108
109 void Cache::load()
110 {
111         if(FS::Stat st = FS::stat(filename))
112         {
113                 package.get_builder().get_logger().log("files", format("Reading %s", filename));
114                 IO::BufferedFile in(filename.str());
115
116                 while(!in.eof())
117                 {
118                         Key key;
119                         key.first = read_string(in);
120                         key.second = read_string(in);
121                         if(key.first.empty() || key.second.empty())
122                                 break;
123                         ValueList &values = data[key];
124                         for(unsigned count = read_count(in); count; --count)
125                                 values.push_back(read_string(in));
126                         package.get_builder().get_logger().log("cache", format("Loaded key %s %s: %s", key.first, key.second, join(values.begin(), values.end())));
127                 }
128
129                 mtime = st.get_modify_time();
130         }
131 }
132
133 void Cache::save() const
134 {
135         if(data.empty() || !changed)
136                 return;
137
138         FS::Path dir = FS::dirname(filename);
139         if(!FS::exists(dir))
140                 FS::mkpath(dir, 0755);
141         package.get_builder().get_logger().log("files", format("Writing %s", filename));
142         IO::BufferedFile out(filename.str(), IO::M_WRITE);
143
144         for(DataMap::const_iterator i=data.begin(); i!=data.end(); ++i)
145         {
146                 write_string(out, i->first.first);
147                 write_string(out, i->first.second);
148                 write_count(out, i->second.size());
149                 for(ValueList::const_iterator j=i->second.begin(); j!=i->second.end(); ++j)
150                         write_string(out, *j);
151         }
152 }