@@ -45,76 +45,79 @@ func GetFile(project devboxProject) (*File, error) {
4545 return lockFile , nil
4646}
4747
48- func (l * File ) Add (pkgs ... string ) error {
48+ func (f * File ) Add (pkgs ... string ) error {
4949 for _ , p := range pkgs {
50- if _ , err := l .Resolve (p ); err != nil {
50+ if _ , err := f .Resolve (p ); err != nil {
5151 return err
5252 }
5353 }
54- return l .Save ()
54+ return f .Save ()
5555}
5656
57- func (l * File ) Remove (pkgs ... string ) error {
57+ func (f * File ) Remove (pkgs ... string ) error {
5858 for _ , p := range pkgs {
59- delete (l .Packages , p )
59+ delete (f .Packages , p )
6060 }
61- return l .Save ()
61+ return f .Save ()
6262}
6363
6464// Resolve updates the in memory copy for performance but does not write to disk
6565// This avoids writing values that may need to be removed in case of error.
66- func (l * File ) Resolve (pkg string ) (* Package , error ) {
67- entry , hasEntry := l .Packages [pkg ]
66+ func (f * File ) Resolve (pkg string ) (* Package , error ) {
67+ entry , hasEntry := f .Packages [pkg ]
6868
6969 if ! hasEntry || entry .Resolved == "" {
7070 locked := & Package {}
7171 var err error
7272 if _ , _ , versioned := searcher .ParseVersionedPackage (pkg ); versioned {
73- locked , err = l .FetchResolvedPackage (pkg )
73+ locked , err = f .FetchResolvedPackage (pkg )
7474 if err != nil {
7575 return nil , err
7676 }
7777 } else if IsLegacyPackage (pkg ) {
7878 // These are legacy packages without a version. Resolve to nixpkgs with
7979 // whatever hash is in the devbox.json
8080 locked = & Package {
81- Resolved : l .LegacyNixpkgsPath (pkg ),
81+ Resolved : f .LegacyNixpkgsPath (pkg ),
8282 Source : nixpkgSource ,
8383 }
8484 }
85- l .Packages [pkg ] = locked
85+ f .Packages [pkg ] = locked
8686 }
8787
88- return l .Packages [pkg ], nil
88+ return f .Packages [pkg ], nil
8989}
9090
91- func (l * File ) ForceResolve (pkg string ) (* Package , error ) {
92- delete (l .Packages , pkg )
93- return l .Resolve (pkg )
91+ func (f * File ) ForceResolve (pkg string ) (* Package , error ) {
92+ delete (f .Packages , pkg )
93+ return f .Resolve (pkg )
9494}
9595
96- func (l * File ) Save () error {
97- return cuecfg .WriteFile (lockFilePath (l .devboxProject ), l )
96+ func (f * File ) Save () error {
97+ if err := cuecfg .WriteFile (lockFilePath (f .devboxProject ), f ); err != nil {
98+ return err
99+ }
100+ return updateLocal (f .devboxProject )
98101}
99102
100- func (l * File ) LegacyNixpkgsPath (pkg string ) string {
103+ func (f * File ) LegacyNixpkgsPath (pkg string ) string {
101104 return fmt .Sprintf (
102105 "github:NixOS/nixpkgs/%s#%s" ,
103- l .NixPkgsCommitHash (),
106+ f .NixPkgsCommitHash (),
104107 pkg ,
105108 )
106109}
107110
108- func (l * File ) Get (pkg string ) * Package {
109- entry , hasEntry := l .Packages [pkg ]
111+ func (f * File ) Get (pkg string ) * Package {
112+ entry , hasEntry := f .Packages [pkg ]
110113 if ! hasEntry || entry .Resolved == "" {
111114 return nil
112115 }
113116 return entry
114117}
115118
116- func (l * File ) HasAllowInsecurePackages () bool {
117- for _ , pkg := range l .Packages {
119+ func (f * File ) HasAllowInsecurePackages () bool {
120+ for _ , pkg := range f .Packages {
118121 if pkg .AllowInsecure {
119122 return true
120123 }
@@ -137,8 +140,36 @@ func IsLegacyPackage(pkg string) bool {
137140
138141// Tidy ensures that the lockfile has the set of packages corresponding to the devbox.json config.
139142// It gets rid of older packages that are no longer needed.
140- func (l * File ) Tidy () {
141- l .Packages = lo .PickByKeys (l .Packages , l .devboxProject .Packages ())
143+ func (f * File ) Tidy () {
144+ f .Packages = lo .PickByKeys (f .Packages , f .devboxProject .Packages ())
145+ }
146+
147+ // IsUpToDateAndInstalled returns true if the lockfile is up to date and the
148+ // local hashes match, which generally indicates all packages are correctly
149+ // installed and print-dev-env has been computed and cached.
150+ func (f * File ) IsUpToDateAndInstalled () (bool , error ) {
151+ if dirty , err := f .isDirty (); err != nil {
152+ return false , err
153+ } else if dirty {
154+ return false , nil
155+ }
156+ return isLocalUpToDate (f .devboxProject )
157+ }
158+
159+ func (f * File ) isDirty () (bool , error ) {
160+ currentHash , err := cuecfg .Hash (f )
161+ if err != nil {
162+ return false , err
163+ }
164+ fileSystemLockFile , err := GetFile (f .devboxProject )
165+ if err != nil {
166+ return false , err
167+ }
168+ filesystemHash , err := cuecfg .Hash (fileSystemLockFile )
169+ if err != nil {
170+ return false , err
171+ }
172+ return currentHash != filesystemHash , nil
142173}
143174
144175func lockFilePath (project devboxProject ) string {
0 commit comments