1 /** @file packagefeed.cpp Links to loaded packages.
2 *
3 * @authors Copyright (c) 2014-2017 Jaakko Keränen <jaakko.keranen@iki.fi>
4 *
5 * @par License
6 * LGPL: http://www.gnu.org/licenses/lgpl.html
7 *
8 * <small>This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU Lesser General Public License as published by
10 * the Free Software Foundation; either version 3 of the License, or (at your
11 * option) any later version. This program is distributed in the hope that it
12 * will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
13 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
14 * General Public License for more details. You should have received a copy of
15 * the GNU Lesser General Public License along with this program; if not, see:
16 * http://www.gnu.org/licenses</small>
17 */
18
19 #include "de/PackageFeed"
20 #include "de/LinkFile"
21 #include "de/ArchiveFolder"
22 #include "de/PackageLoader"
23 #include "de/FS"
24
25 namespace de {
26
27 static String const VAR_LINK_PACKAGE_ID("link.package");
28
DENG2_PIMPL(PackageFeed)29 DENG2_PIMPL(PackageFeed)
30 {
31 PackageLoader &loader;
32 LinkMode linkMode;
33 Filter filter;
34
35 Impl(Public *i, PackageLoader &ldr, LinkMode lm)
36 : Base(i), loader(ldr), linkMode(lm)
37 {}
38
39 File *linkToPackage(Package &pkg, String const &linkName, Folder const &folder)
40 {
41 /// @todo Resolve conflicts: replace, ignore, or fail. -jk
42
43 if (folder.has(linkName)) return nullptr; // Already there, keep the existing link.
44
45 // Packages can be optionally filtered from the feed.
46 if (filter && !filter(pkg)) return nullptr;
47
48 // Create a link to the loaded package's file.
49 String name;
50 if (linkMode == LinkIdentifier)
51 {
52 name = linkName;
53 }
54 else
55 {
56 name = Package::versionedIdentifierForFile(pkg.file());
57 }
58 LinkFile *link = LinkFile::newLinkToFile(pkg.file(), name);
59
60 // We will decide on pruning this.
61 link->setOriginFeed(thisPublic);
62
63 // Identifier also in metadata.
64 link->objectNamespace().addText(VAR_LINK_PACKAGE_ID, pkg.identifier());
65
66 return link;
67 }
68
69 PopulatedFiles populate(Folder const &folder)
70 {
71 PopulatedFiles populated;
72 DENG2_FOR_EACH_CONST(PackageLoader::LoadedPackages, i, loader.loadedPackages())
73 {
74 Package *pkg = i.value();
75 populated << linkToPackage(*pkg, i.key(), folder);
76
77 // Also link it under its possible alias identifier (for variants).
78 if (pkg->objectNamespace().has(Package::VAR_PACKAGE_ALIAS))
79 {
80 populated << linkToPackage(*pkg, pkg->objectNamespace()
81 .gets(Package::VAR_PACKAGE_ALIAS), folder);
82 }
83
84 // Link each contained asset, too.
85 foreach (String ident, pkg->assets())
86 {
87 populated << linkToPackage(*pkg, "asset." + ident, folder);
88 }
89 }
90 return populated;
91 }
92 };
93
PackageFeed(PackageLoader & loader,LinkMode linkMode)94 PackageFeed::PackageFeed(PackageLoader &loader, LinkMode linkMode)
95 : d(new Impl(this, loader, linkMode))
96 {}
97
setFilter(Filter filter)98 void PackageFeed::setFilter(Filter filter)
99 {
100 d->filter = filter;
101 }
102
loader()103 PackageLoader &PackageFeed::loader()
104 {
105 return d->loader;
106 }
107
description() const108 String PackageFeed::description() const
109 {
110 return "loaded packages";
111 }
112
populate(Folder const & folder)113 Feed::PopulatedFiles PackageFeed::populate(Folder const &folder)
114 {
115 return d->populate(folder);
116 }
117
prune(File & file) const118 bool PackageFeed::prune(File &file) const
119 {
120 if (LinkFile const *link = maybeAs<LinkFile>(file))
121 {
122 // Links to unloaded packages should be pruned.
123 if (!d->loader.isLoaded(link->objectNamespace().gets(VAR_LINK_PACKAGE_ID)))
124 return true;
125
126 //if (Folder const *pkg = maybeAs<Folder>(link->target()))
127 {
128 // Links to unloaded packages should be pruned.
129 //if (!d->loader.isLoaded(*pkg)) return true;
130
131 // qDebug() << "Link:" << link->description() << link->status().modifiedAt.asText();
132 // qDebug() << " tgt:" << link->target().description() << link->target().status().modifiedAt.asText();
133
134 // Package has been modified, should be pruned.
135 if (link->status() != link->target().status()) return true;
136 }
137 }
138 return false; // Don't prune.
139 }
140
141 } // namespace de
142