chr
2026-04-05 fe750b791d5b517cc4e9bc8e99a9a75139a0cfba
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
//            Copyright Keysight Technologies 2012-2019
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, you can obtain one at http://mozilla.org/MPL/2.0/.
 
using System;
using System.IO;
using Tap.Shared;
 
namespace OpenTap.Package
{
    static class PackageCacheHelper
    {
        // ApplicationDataLocal is meant for storing data for the local(non-roaming) user. E.g, if the user logs
        // into another machine that data should not be copied over. It needs to be a location that can be written to
        // by the current user without any additional rights - hence it cannot be truly system-wide.
        // Resolves to:
        // - Linux: /home/<USER>/.local/share/OpenTAP/PackageCache
        // - Windows: C:\Users\<USER>\AppData\Local\OpenTAP\PackageCache
        //
        // Unless OPENTAP_PACKAGE_CACHE_DIR is set, then that path will be used instead.
        public static string PackageCacheDirectory
        {
            get
            {
                var alt = Environment.GetEnvironmentVariable(PackageCacheOverrideEnvironmentVariable);
                if (string.IsNullOrWhiteSpace(alt) == false)
                    return alt;
                return Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData, Environment.SpecialFolderOption.Create), "OpenTap", "PackageCache");
            }
        } 
 
        const string PackageCacheOverrideEnvironmentVariable = "OPENTAP_PACKAGE_CACHE_DIR";
        
        readonly static TraceSource log =  Log.CreateSource("PackageCache");
 
        static PackageCacheHelper()
        {
            Directory.CreateDirectory(PackageCacheDirectory);
        }
 
        internal static string GetCacheFilePath(PackageDef package)
        {
            var packageName = PackageActionHelpers.GetQualifiedFileName(package).Replace('/', '.'); // TODO: use the hash in this name, to be able to handle cross repo name clashes.
            return Path.Combine(PackageCacheHelper.PackageCacheDirectory, packageName);
        }
 
        internal static bool PackageIsFromCache(PackageDef package)
        {
            return (package.PackageSource as IRepositoryPackageDefSource)?.RepositoryUrl.StartsWith(PackageCacheDirectory) == true;
        }
        
        internal static void CachePackage(string filename)
        {
            if (!File.Exists(filename))
                throw new FileNotFoundException(filename);
 
            string newFilename = Path.Combine(PackageCacheDirectory, Path.GetFileName(filename));
            
            // return early to avoid multiple processes interfering with each other. 
            if (File.Exists(newFilename) && PathUtils.CompareFiles(filename,newFilename)) return;
 
            if (filename == newFilename)
                return;
 
            File.Copy(filename, newFilename, true);
            log.Debug("Package cached in {0}.", newFilename);
        }
 
        internal static void ClearCache()
        {
            Directory.Delete(PackageCacheDirectory, true);
            Directory.CreateDirectory(PackageCacheDirectory);
        }
    }
}